* 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.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@39035 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Stephan Aßmus
2010-10-20 21:36:23 +00:00
parent 6e544b050e
commit 69372b5545
7 changed files with 50 additions and 45 deletions
+1 -2
View File
@@ -227,8 +227,7 @@ private:
// 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();
+3 -4
View File
@@ -1,6 +1,6 @@
/*
* Copyright 2009, Stephan Aßmus <[email protected]>. All rights reserved.
* Distributed under the terms of the MIT License.
* Copyright 2009-2010, Stephan Aßmus <[email protected]>.
* All rights reserved. Distributed under the terms of the MIT License.
*/
#ifndef _MEDIA_WRITER_H
#define _MEDIA_WRITER_H
@@ -27,8 +27,7 @@ public:
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);
+1 -1
View File
@@ -21,7 +21,7 @@ public:
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;
@@ -61,7 +61,7 @@ public:
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 @@ AVFormatWriter::StreamCookie::~StreamCookie()
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 @@ AVFormatWriter::StreamCookie::Init(const media_format* format,
// 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 @@ AVFormatWriter::StreamCookie::Init(const media_format* format,
// 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 @@ AVFormatWriter::StreamCookie::Init(const media_format* format,
fStream->codec->height, 255);
}
fStream->codec->sample_aspect_ratio = fStream->sample_aspect_ratio;
// TODO: Don't hard code this...
fStream->codec->pix_fmt = PIX_FMT_YUV420P;
fStream->codec->gop_size = 12;
fStream->codec->sample_aspect_ratio = fStream->sample_aspect_ratio;
// 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];
// Some formats want stream headers to be separate
if ((fContext->oformat->flags & AVFMT_GLOBALHEADER) != 0)
fStream->codec->flags |= CODEC_FLAG_GLOBAL_HEADER;
} 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 @@ AVFormatWriter::StreamCookie::Init(const media_format* format,
}
}
// 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 @@ AVFormatWriter::StreamCookie::WriteChunk(const void* chunkBuffer,
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 @@ AVFormatWriter::CommitHeader()
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 @@ AVFormatWriter::CommitHeader()
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 @@ AVFormatWriter::Close()
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");
@@ -28,7 +28,7 @@ public:
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);
+14 -4
View File
@@ -331,6 +331,14 @@ BMediaTrack::ReadFrames(void* buffer, int64* _frameCount,
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::MediaExtractor* extractor,
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 @@ BMediaTrack::BMediaTrack(BPrivate::media::MediaWriter* writer,
fEncoderID = -1;
// TODO: Not yet sure what this was needed for...
fWriter = writer;
fFormat = *format;
fStream = streamIndex;
fInitStatus = B_OK;
@@ -803,14 +810,17 @@ BMediaTrack::BMediaTrack(BPrivate::media::MediaWriter* writer,
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;
+3 -4
View File
@@ -1,6 +1,6 @@
/*
* Copyright 2009, Stephan Aßmus <superstippi@gmx.de>. All rights reserved.
* Distributed under the terms of the MIT license.
* Copyright 2009-2010, Stephan Aßmus <superstippi@gmx.de>.
* All rights reserved. Distributed under the terms of the MIT license.
*/
@@ -96,8 +96,7 @@ MediaWriter::GetFileFormatInfo(media_file_format* _fileFormat) const
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();