* 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
|
// For write-only access to a BMediaTrack
|
||||||
BMediaTrack(
|
BMediaTrack(
|
||||||
BPrivate::media::MediaWriter* writer,
|
BPrivate::media::MediaWriter* writer,
|
||||||
int32 streamIndex,
|
int32 streamIndex, media_format* format,
|
||||||
const media_format* format,
|
|
||||||
const media_codec_info* codecInfo);
|
const media_codec_info* codecInfo);
|
||||||
|
|
||||||
void SetupWorkaround();
|
void SetupWorkaround();
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2009, Stephan Aßmus <[email protected]>. All rights reserved.
|
* Copyright 2009-2010, Stephan Aßmus <[email protected]>.
|
||||||
* Distributed under the terms of the MIT License.
|
* All rights reserved. Distributed under the terms of the MIT License.
|
||||||
*/
|
*/
|
||||||
#ifndef _MEDIA_WRITER_H
|
#ifndef _MEDIA_WRITER_H
|
||||||
#define _MEDIA_WRITER_H
|
#define _MEDIA_WRITER_H
|
||||||
@@ -27,8 +27,7 @@ public:
|
|||||||
|
|
||||||
status_t CreateEncoder(Encoder** _encoder,
|
status_t CreateEncoder(Encoder** _encoder,
|
||||||
const media_codec_info* codecInfo,
|
const media_codec_info* codecInfo,
|
||||||
const media_format* format,
|
media_format* format, uint32 flags = 0);
|
||||||
uint32 flags = 0);
|
|
||||||
|
|
||||||
status_t SetCopyright(int32 streamIndex,
|
status_t SetCopyright(int32 streamIndex,
|
||||||
const char* copyright);
|
const char* copyright);
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ public:
|
|||||||
virtual status_t Close() = 0;
|
virtual status_t Close() = 0;
|
||||||
|
|
||||||
virtual status_t AllocateCookie(void** cookie,
|
virtual status_t AllocateCookie(void** cookie,
|
||||||
const media_format* format,
|
media_format* format,
|
||||||
const media_codec_info* codecInfo) = 0;
|
const media_codec_info* codecInfo) = 0;
|
||||||
virtual status_t FreeCookie(void* cookie) = 0;
|
virtual status_t FreeCookie(void* cookie) = 0;
|
||||||
|
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ public:
|
|||||||
BLocker* streamLock);
|
BLocker* streamLock);
|
||||||
virtual ~StreamCookie();
|
virtual ~StreamCookie();
|
||||||
|
|
||||||
status_t Init(const media_format* format,
|
status_t Init(media_format* format,
|
||||||
const media_codec_info* codecInfo);
|
const media_codec_info* codecInfo);
|
||||||
|
|
||||||
status_t WriteChunk(const void* chunkBuffer,
|
status_t WriteChunk(const void* chunkBuffer,
|
||||||
@@ -99,7 +99,7 @@ AVFormatWriter::StreamCookie::~StreamCookie()
|
|||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
AVFormatWriter::StreamCookie::Init(const media_format* format,
|
AVFormatWriter::StreamCookie::Init(media_format* format,
|
||||||
const media_codec_info* codecInfo)
|
const media_codec_info* codecInfo)
|
||||||
{
|
{
|
||||||
TRACE("AVFormatWriter::StreamCookie::Init()\n");
|
TRACE("AVFormatWriter::StreamCookie::Init()\n");
|
||||||
@@ -123,7 +123,7 @@ AVFormatWriter::StreamCookie::Init(const media_format* format,
|
|||||||
|
|
||||||
// Setup the stream according to the media format...
|
// Setup the stream according to the media format...
|
||||||
if (format->type == B_MEDIA_RAW_VIDEO) {
|
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
|
#if GET_CONTEXT_DEFAULTS
|
||||||
// NOTE: API example does not do this:
|
// NOTE: API example does not do this:
|
||||||
avcodec_get_context_defaults(fStream->codec);
|
avcodec_get_context_defaults(fStream->codec);
|
||||||
@@ -131,11 +131,6 @@ AVFormatWriter::StreamCookie::Init(const media_format* format,
|
|||||||
// frame rate
|
// frame rate
|
||||||
fStream->codec->time_base.den = (int)format->u.raw_video.field_rate;
|
fStream->codec->time_base.den = (int)format->u.raw_video.field_rate;
|
||||||
fStream->codec->time_base.num = 1;
|
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
|
// video size
|
||||||
fStream->codec->width = format->u.raw_video.display.line_width;
|
fStream->codec->width = format->u.raw_video.display.line_width;
|
||||||
fStream->codec->height = format->u.raw_video.display.line_count;
|
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->height, 255);
|
||||||
}
|
}
|
||||||
|
|
||||||
fStream->codec->sample_aspect_ratio = fStream->sample_aspect_ratio;
|
fStream->codec->gop_size = 12;
|
||||||
// TODO: Don't hard code this...
|
|
||||||
fStream->codec->pix_fmt = PIX_FMT_YUV420P;
|
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) {
|
} 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
|
#if GET_CONTEXT_DEFAULTS
|
||||||
// NOTE: API example does not do this:
|
// NOTE: API example does not do this:
|
||||||
avcodec_get_context_defaults(fStream->codec);
|
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",
|
TRACE(" stream->time_base: (%d/%d), codec->time_base: (%d/%d))\n",
|
||||||
fStream->time_base.num, fStream->time_base.den,
|
fStream->time_base.num, fStream->time_base.den,
|
||||||
fStream->codec->time_base.num, fStream->codec->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);
|
BAutolock _(fStreamLock);
|
||||||
|
|
||||||
// TODO: Probably the AVCodecEncoder needs to pass packet data
|
|
||||||
// in encodeInfo...
|
|
||||||
|
|
||||||
fPacket.data = const_cast<uint8_t*>((const uint8_t*)chunkBuffer);
|
fPacket.data = const_cast<uint8_t*>((const uint8_t*)chunkBuffer);
|
||||||
fPacket.size = chunkSize;
|
fPacket.size = chunkSize;
|
||||||
|
|
||||||
fPacket.pts = int64_t((double)encodeInfo->start_time
|
fPacket.pts = int64_t((double)encodeInfo->start_time
|
||||||
* fStream->time_base.den / (1000000.0 * fStream->time_base.num)
|
* fStream->time_base.den / (1000000.0 * fStream->time_base.num)
|
||||||
+ 0.5);
|
+ 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,
|
"codec->time_base: (%d/%d))\n", fPacket.pts,
|
||||||
fStream->time_base.num, fStream->time_base.den,
|
fStream->time_base.num, fStream->time_base.den,
|
||||||
fStream->codec->time_base.num, fStream->codec->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
|
#if 0
|
||||||
// TODO: Eventually, we need to write interleaved packets, but
|
// TODO: Eventually, we need to write interleaved packets, but
|
||||||
// maybe we are only supposed to use this if we have actually
|
// 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)
|
if (av_set_parameters(fContext, NULL) < 0)
|
||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
|
|
||||||
|
#if OPEN_CODEC_CONTEXT
|
||||||
for (unsigned i = 0; i < fContext->nb_streams; i++) {
|
for (unsigned i = 0; i < fContext->nb_streams; i++) {
|
||||||
AVStream* stream = fContext->streams[i];
|
AVStream* stream = fContext->streams[i];
|
||||||
#if OPEN_CODEC_CONTEXT
|
|
||||||
// NOTE: Experimental, this should not be needed. Especially, since
|
// NOTE: Experimental, this should not be needed. Especially, since
|
||||||
// we have no idea (in the future) what CodecID some encoder uses,
|
// we have no idea (in the future) what CodecID some encoder uses,
|
||||||
// it may be an encoder from a different plugin.
|
// it may be an encoder from a different plugin.
|
||||||
@@ -407,11 +405,11 @@ AVFormatWriter::CommitHeader()
|
|||||||
if (codec == NULL || avcodec_open(codecContext, codec) < 0) {
|
if (codec == NULL || avcodec_open(codecContext, codec) < 0) {
|
||||||
TRACE(" stream[%u] - failed to open AVCodecContext\n", i);
|
TRACE(" stream[%u] - failed to open AVCodecContext\n", i);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
TRACE(" stream[%u] time_base: (%d/%d), codec->time_base: (%d/%d)\n",
|
TRACE(" stream[%u] time_base: (%d/%d), codec->time_base: (%d/%d)\n",
|
||||||
i, stream->time_base.num, stream->time_base.den,
|
i, stream->time_base.num, stream->time_base.den,
|
||||||
stream->codec->time_base.num, stream->codec->time_base.den);
|
stream->codec->time_base.num, stream->codec->time_base.den);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
int result = av_write_header(fContext);
|
int result = av_write_header(fContext);
|
||||||
if (result < 0)
|
if (result < 0)
|
||||||
@@ -463,7 +461,7 @@ AVFormatWriter::Close()
|
|||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
AVFormatWriter::AllocateCookie(void** _cookie, const media_format* format,
|
AVFormatWriter::AllocateCookie(void** _cookie, media_format* format,
|
||||||
const media_codec_info* codecInfo)
|
const media_codec_info* codecInfo)
|
||||||
{
|
{
|
||||||
TRACE("AVFormatWriter::AllocateCookie()\n");
|
TRACE("AVFormatWriter::AllocateCookie()\n");
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ public:
|
|||||||
virtual status_t Close();
|
virtual status_t Close();
|
||||||
|
|
||||||
virtual status_t AllocateCookie(void** cookie,
|
virtual status_t AllocateCookie(void** cookie,
|
||||||
const media_format* format,
|
media_format* format,
|
||||||
const media_codec_info* codecInfo);
|
const media_codec_info* codecInfo);
|
||||||
virtual status_t FreeCookie(void* cookie);
|
virtual status_t FreeCookie(void* cookie);
|
||||||
|
|
||||||
|
|||||||
@@ -331,6 +331,14 @@ BMediaTrack::ReadFrames(void* buffer, int64* _frameCount,
|
|||||||
bigtime_t framesDuration = (bigtime_t)(*_frameCount * 1000000
|
bigtime_t framesDuration = (bigtime_t)(*_frameCount * 1000000
|
||||||
/ _FrameRate());
|
/ _FrameRate());
|
||||||
fCurrentTime = _header->start_time + framesDuration;
|
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 {
|
} else {
|
||||||
ERROR("BMediaTrack::ReadFrames: decoder returned error 0x%08lx (%s)\n",
|
ERROR("BMediaTrack::ReadFrames: decoder returned error 0x%08lx (%s)\n",
|
||||||
result, strerror(result));
|
result, strerror(result));
|
||||||
@@ -782,7 +790,7 @@ BMediaTrack::BMediaTrack(BPrivate::media::MediaExtractor* extractor,
|
|||||||
|
|
||||||
|
|
||||||
BMediaTrack::BMediaTrack(BPrivate::media::MediaWriter* writer,
|
BMediaTrack::BMediaTrack(BPrivate::media::MediaWriter* writer,
|
||||||
int32 streamIndex, const media_format* format,
|
int32 streamIndex, media_format* format,
|
||||||
const media_codec_info* codecInfo)
|
const media_codec_info* codecInfo)
|
||||||
{
|
{
|
||||||
CALLED();
|
CALLED();
|
||||||
@@ -792,7 +800,6 @@ BMediaTrack::BMediaTrack(BPrivate::media::MediaWriter* writer,
|
|||||||
fEncoderID = -1;
|
fEncoderID = -1;
|
||||||
// TODO: Not yet sure what this was needed for...
|
// TODO: Not yet sure what this was needed for...
|
||||||
fWriter = writer;
|
fWriter = writer;
|
||||||
fFormat = *format;
|
|
||||||
fStream = streamIndex;
|
fStream = streamIndex;
|
||||||
fInitStatus = B_OK;
|
fInitStatus = B_OK;
|
||||||
|
|
||||||
@@ -803,14 +810,17 @@ BMediaTrack::BMediaTrack(BPrivate::media::MediaWriter* writer,
|
|||||||
if (ret != B_OK) {
|
if (ret != B_OK) {
|
||||||
TRACE("BMediaTrack::BMediaTrack: Error: creating decoder failed: "
|
TRACE("BMediaTrack::BMediaTrack: Error: creating decoder failed: "
|
||||||
"%s\n", strerror(ret));
|
"%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;
|
fEncoder = NULL;
|
||||||
} else {
|
} else {
|
||||||
fCodecInfo = *codecInfo;
|
fCodecInfo = *codecInfo;
|
||||||
fInitStatus = fEncoder->SetUp(&fFormat);
|
fInitStatus = fEncoder->SetUp(format);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fFormat = *format;
|
||||||
|
|
||||||
// not used:
|
// not used:
|
||||||
fCurrentFrame = 0;
|
fCurrentFrame = 0;
|
||||||
fCurrentTime = 0;
|
fCurrentTime = 0;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2009, Stephan Aßmus <[email protected]>. All rights reserved.
|
* Copyright 2009-2010, Stephan Aßmus <[email protected]>.
|
||||||
* Distributed under the terms of the MIT license.
|
* All rights reserved. Distributed under the terms of the MIT license.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
@@ -96,8 +96,7 @@ MediaWriter::GetFileFormatInfo(media_file_format* _fileFormat) const
|
|||||||
|
|
||||||
status_t
|
status_t
|
||||||
MediaWriter::CreateEncoder(Encoder** _encoder,
|
MediaWriter::CreateEncoder(Encoder** _encoder,
|
||||||
const media_codec_info* codecInfo, const media_format* format,
|
const media_codec_info* codecInfo, media_format* format, uint32 flags)
|
||||||
uint32 flags)
|
|
||||||
{
|
{
|
||||||
CALLED();
|
CALLED();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user