Author: stippi Date: 2010-10-20 23:36:23 +0200 (Wed, 20 Oct 2010) New Revision: 39035 Changeset: http://dev.haiku-os.org/changeset/39035 Modified: haiku/trunk/headers/os/media/MediaTrack.h haiku/trunk/headers/private/media/MediaWriter.h haiku/trunk/headers/private/media/WriterPlugin.h haiku/trunk/src/add-ons/media/plugins/ffmpeg/AVFormatWriter.cpp haiku/trunk/src/add-ons/media/plugins/ffmpeg/AVFormatWriter.h haiku/trunk/src/kits/media/MediaTrack.cpp haiku/trunk/src/kits/media/MediaWriter.cpp Log: * Change the signature of the Writer plugins setup methods such that they can modify the media_format passed in. For example they can store information in the user_data section. I don't actually use this anymore, but it may come in handy again. AVFormatWriter: * Adjust the AVCodecContext flags not only for video, but also for audio streams (as the API example does). This mechanism may not yet work, since the AVCodecEncoder actually uses a different AVCodecContext instance. * Use the encodeInfo->flags and specify the key frame flag for the AVPacket. This finally makes videos encoded on Haiku seekable. Modified: haiku/trunk/headers/os/media/MediaTrack.h =================================================================== --- haiku/trunk/headers/os/media/MediaTrack.h 2010-10-20 21:29:16 UTC (rev 39034) +++ haiku/trunk/headers/os/media/MediaTrack.h 2010-10-20 21:36:23 UTC (rev 39035) @@ -227,8 +227,7 @@ // For write-only access to a BMediaTrack BMediaTrack( BPrivate::media::MediaWriter* writer, - int32 streamIndex, - const media_format* format, + int32 streamIndex, media_format* format, const media_codec_info* codecInfo); void SetupWorkaround(); Modified: haiku/trunk/headers/private/media/MediaWriter.h =================================================================== --- haiku/trunk/headers/private/media/MediaWriter.h 2010-10-20 21:29:16 UTC (rev 39034) +++ haiku/trunk/headers/private/media/MediaWriter.h 2010-10-20 21:36:23 UTC (rev 39035) @@ -1,6 +1,6 @@ /* - * Copyright 2009, Stephan Aßmus <superstippi@xxxxxx>. All rights reserved. - * Distributed under the terms of the MIT License. + * Copyright 2009-2010, Stephan Aßmus <superstippi@xxxxxx>. + * All rights reserved. Distributed under the terms of the MIT License. */ #ifndef _MEDIA_WRITER_H #define _MEDIA_WRITER_H @@ -27,8 +27,7 @@ status_t CreateEncoder(Encoder** _encoder, const media_codec_info* codecInfo, - const media_format* format, - uint32 flags = 0); + media_format* format, uint32 flags = 0); status_t SetCopyright(int32 streamIndex, const char* copyright); Modified: haiku/trunk/headers/private/media/WriterPlugin.h =================================================================== --- haiku/trunk/headers/private/media/WriterPlugin.h 2010-10-20 21:29:16 UTC (rev 39034) +++ haiku/trunk/headers/private/media/WriterPlugin.h 2010-10-20 21:36:23 UTC (rev 39035) @@ -21,7 +21,7 @@ virtual status_t Close() = 0; virtual status_t AllocateCookie(void** cookie, - const media_format* format, + media_format* format, const media_codec_info* codecInfo) = 0; virtual status_t FreeCookie(void* cookie) = 0; Modified: haiku/trunk/src/add-ons/media/plugins/ffmpeg/AVFormatWriter.cpp =================================================================== --- haiku/trunk/src/add-ons/media/plugins/ffmpeg/AVFormatWriter.cpp 2010-10-20 21:29:16 UTC (rev 39034) +++ haiku/trunk/src/add-ons/media/plugins/ffmpeg/AVFormatWriter.cpp 2010-10-20 21:36:23 UTC (rev 39035) @@ -61,7 +61,7 @@ BLocker* streamLock); virtual ~StreamCookie(); - status_t Init(const media_format* format, + status_t Init(media_format* format, const media_codec_info* codecInfo); status_t WriteChunk(const void* chunkBuffer, @@ -99,7 +99,7 @@ status_t -AVFormatWriter::StreamCookie::Init(const media_format* format, +AVFormatWriter::StreamCookie::Init(media_format* format, const media_codec_info* codecInfo) { TRACE("AVFormatWriter::StreamCookie::Init()\n"); @@ -123,7 +123,7 @@ // Setup the stream according to the media format... if (format->type == B_MEDIA_RAW_VIDEO) { - fStream->codec->codec_type = CODEC_TYPE_VIDEO; + fStream->codec->codec_type = AVMEDIA_TYPE_VIDEO; #if GET_CONTEXT_DEFAULTS // NOTE: API example does not do this: avcodec_get_context_defaults(fStream->codec); @@ -131,11 +131,6 @@ // frame rate fStream->codec->time_base.den = (int)format->u.raw_video.field_rate; fStream->codec->time_base.num = 1; -// NOTE: API example does not do this: -// fStream->r_frame_rate.den = (int)format->u.raw_video.field_rate; -// fStream->r_frame_rate.num = 1; -// fStream->time_base.den = (int)format->u.raw_video.field_rate; -// fStream->time_base.num = 1; // video size fStream->codec->width = format->u.raw_video.display.line_width; fStream->codec->height = format->u.raw_video.display.line_count; @@ -151,15 +146,19 @@ fStream->codec->height, 255); } + fStream->codec->gop_size = 12; + fStream->codec->sample_aspect_ratio = fStream->sample_aspect_ratio; - // TODO: Don't hard code this... - fStream->codec->pix_fmt = PIX_FMT_YUV420P; - // Some formats want stream headers to be separate - if ((fContext->oformat->flags & AVFMT_GLOBALHEADER) != 0) - fStream->codec->flags |= CODEC_FLAG_GLOBAL_HEADER; + // Use the last supported pixel format of the AVCodec, which we hope + // is the one with the best quality (true for all currently supported + // encoders). + AVCodec* codec = fStream->codec->codec; + for (int i = 0; codec->pix_fmts[i] != PIX_FMT_NONE; i++) + fStream->codec->pix_fmt = codec->pix_fmts[i]; + } else if (format->type == B_MEDIA_RAW_AUDIO) { - fStream->codec->codec_type = CODEC_TYPE_AUDIO; + fStream->codec->codec_type = AVMEDIA_TYPE_AUDIO; #if GET_CONTEXT_DEFAULTS // NOTE: API example does not do this: avcodec_get_context_defaults(fStream->codec); @@ -226,6 +225,10 @@ } } + // Some formats want stream headers to be separate + if ((fContext->oformat->flags & AVFMT_GLOBALHEADER) != 0) + fStream->codec->flags |= CODEC_FLAG_GLOBAL_HEADER; + TRACE(" stream->time_base: (%d/%d), codec->time_base: (%d/%d))\n", fStream->time_base.num, fStream->time_base.den, fStream->codec->time_base.num, fStream->codec->time_base.den); @@ -244,27 +247,22 @@ BAutolock _(fStreamLock); - // TODO: Probably the AVCodecEncoder needs to pass packet data - // in encodeInfo... - fPacket.data = const_cast<uint8_t*>((const uint8_t*)chunkBuffer); fPacket.size = chunkSize; fPacket.pts = int64_t((double)encodeInfo->start_time * fStream->time_base.den / (1000000.0 * fStream->time_base.num) + 0.5); - TRACE_PACKET(" PTS: %lld (stream->time_base: (%d/%d), " + + fPacket.flags = 0; + if ((encodeInfo->flags & B_MEDIA_KEY_FRAME) != 0) + fPacket.flags |= AV_PKT_FLAG_KEY; + + TRACE_PACKET(" PTS: %lld (stream->time_base: (%d/%d), " "codec->time_base: (%d/%d))\n", fPacket.pts, fStream->time_base.num, fStream->time_base.den, fStream->codec->time_base.num, fStream->codec->time_base.den); -// From ffmpeg.c::do_audio_out(): -// TODO: -// if (enc->coded_frame && enc->coded_frame->pts != AV_NOPTS_VALUE) -// fPacket.pts = av_rescale_q(enc->coded_frame->pts, -// enc->time_base, ost->st->time_base); - - #if 0 // TODO: Eventually, we need to write interleaved packets, but // maybe we are only supposed to use this if we have actually @@ -396,9 +394,9 @@ if (av_set_parameters(fContext, NULL) < 0) return B_ERROR; +#if OPEN_CODEC_CONTEXT for (unsigned i = 0; i < fContext->nb_streams; i++) { AVStream* stream = fContext->streams[i]; -#if OPEN_CODEC_CONTEXT // NOTE: Experimental, this should not be needed. Especially, since // we have no idea (in the future) what CodecID some encoder uses, // it may be an encoder from a different plugin. @@ -407,11 +405,11 @@ if (codec == NULL || avcodec_open(codecContext, codec) < 0) { TRACE(" stream[%u] - failed to open AVCodecContext\n", i); } -#endif TRACE(" stream[%u] time_base: (%d/%d), codec->time_base: (%d/%d)\n", i, stream->time_base.num, stream->time_base.den, stream->codec->time_base.num, stream->codec->time_base.den); } +#endif int result = av_write_header(fContext); if (result < 0) @@ -463,7 +461,7 @@ status_t -AVFormatWriter::AllocateCookie(void** _cookie, const media_format* format, +AVFormatWriter::AllocateCookie(void** _cookie, media_format* format, const media_codec_info* codecInfo) { TRACE("AVFormatWriter::AllocateCookie()\n"); Modified: haiku/trunk/src/add-ons/media/plugins/ffmpeg/AVFormatWriter.h =================================================================== --- haiku/trunk/src/add-ons/media/plugins/ffmpeg/AVFormatWriter.h 2010-10-20 21:29:16 UTC (rev 39034) +++ haiku/trunk/src/add-ons/media/plugins/ffmpeg/AVFormatWriter.h 2010-10-20 21:36:23 UTC (rev 39035) @@ -28,7 +28,7 @@ virtual status_t Close(); virtual status_t AllocateCookie(void** cookie, - const media_format* format, + media_format* format, const media_codec_info* codecInfo); virtual status_t FreeCookie(void* cookie); Modified: haiku/trunk/src/kits/media/MediaTrack.cpp =================================================================== --- haiku/trunk/src/kits/media/MediaTrack.cpp 2010-10-20 21:29:16 UTC (rev 39034) +++ haiku/trunk/src/kits/media/MediaTrack.cpp 2010-10-20 21:36:23 UTC (rev 39035) @@ -331,6 +331,14 @@ bigtime_t framesDuration = (bigtime_t)(*_frameCount * 1000000 / _FrameRate()); fCurrentTime = _header->start_time + framesDuration; +// This debug output shows drift between calculated fCurrentFrame and time-based +// current frame, if there is any. +//if (fFormat.type == B_MEDIA_RAW_AUDIO) { +//printf("current frame: %lld / calculated: %lld (%.2f/%.2f)\r", fCurrentFrame, +//int64(fCurrentTime * _FrameRate() / 1000000.0 + 0.5), fCurrentTime / 1000000.0, +//(float)fCurrentFrame / _FrameRate()); +//fflush(stdout); +//} } else { ERROR("BMediaTrack::ReadFrames: decoder returned error 0x%08lx (%s)\n", result, strerror(result)); @@ -782,7 +790,7 @@ BMediaTrack::BMediaTrack(BPrivate::media::MediaWriter* writer, - int32 streamIndex, const media_format* format, + int32 streamIndex, media_format* format, const media_codec_info* codecInfo) { CALLED(); @@ -792,7 +800,6 @@ fEncoderID = -1; // TODO: Not yet sure what this was needed for... fWriter = writer; - fFormat = *format; fStream = streamIndex; fInitStatus = B_OK; @@ -803,14 +810,17 @@ if (ret != B_OK) { TRACE("BMediaTrack::BMediaTrack: Error: creating decoder failed: " "%s\n", strerror(ret)); - // We do not set fInitStatus here, because WriteChunk should still work. + // We do not set fInitStatus here, because WriteChunk should still + // work. fEncoder = NULL; } else { fCodecInfo = *codecInfo; - fInitStatus = fEncoder->SetUp(&fFormat); + fInitStatus = fEncoder->SetUp(format); } } + fFormat = *format; + // not used: fCurrentFrame = 0; fCurrentTime = 0; Modified: haiku/trunk/src/kits/media/MediaWriter.cpp =================================================================== --- haiku/trunk/src/kits/media/MediaWriter.cpp 2010-10-20 21:29:16 UTC (rev 39034) +++ haiku/trunk/src/kits/media/MediaWriter.cpp 2010-10-20 21:36:23 UTC (rev 39035) @@ -1,6 +1,6 @@ /* - * Copyright 2009, Stephan Aßmus <superstippi@xxxxxx>. All rights reserved. - * Distributed under the terms of the MIT license. + * Copyright 2009-2010, Stephan Aßmus <superstippi@xxxxxx>. + * All rights reserved. Distributed under the terms of the MIT license. */ @@ -96,8 +96,7 @@ status_t MediaWriter::CreateEncoder(Encoder** _encoder, - const media_codec_info* codecInfo, const media_format* format, - uint32 flags) + const media_codec_info* codecInfo, media_format* format, uint32 flags) { CALLED();