* 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:
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user