From 6780c24d36ada936c1d3a1095d2ed9730ef1e0c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stephan=20A=C3=9Fmus?= Date: Wed, 5 Aug 2009 10:21:36 +0000 Subject: [PATCH] Encoder: * Fleshed out the Encoder API to support parameter setters/getters and returning a BView for configuration. (Not yet sure if this is a good idea.) BMediaTrack: * Implemented all but one of the unimplemented methods in BMediaTrack. It should be working as far as that class is concerned, unless I missed some of the vision. ReplaceFrames() remains a stub, added a comment on why it probably stays that way. * Release the Encoder reference in the destructor. FFmpeg plugin: * Refactoring to delay opening the AVCodec until encoding the first chunk, so that we can still adjust parameters. * Support adjusting parameters via [Set|Get]EncodeParameters(). Currently, only quality is supported, added TODOs about supporting the bit_rate setup versus the automatically calculated bit_rate. * Extended EncoderDescription by a bit_rate scale. The Encoder calculates the raw bitrate needed by the current media format, and then divides that number by the specific codec's bit_rate_scale, while taking into account the desired quality. This seems to work very well already (tested with MPEG4), although a lot more parameters could be specified for libavcodec, depending on the desired quality. * Enabled the ogg muxer in libavformat, although it is currently still disabled in MuxerTable.cpp, because it rejects unknown codecs. Added TODO to this effect. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@32124 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- headers/private/media/EncoderPlugin.h | 46 +++- .../media/plugins/ffmpeg/AVCodecEncoder.cpp | 201 ++++++++++++++---- .../media/plugins/ffmpeg/AVCodecEncoder.h | 20 +- .../media/plugins/ffmpeg/EncoderTable.cpp | 15 +- .../media/plugins/ffmpeg/EncoderTable.h | 1 + .../media/plugins/ffmpeg/FFmpegPlugin.cpp | 8 +- .../media/plugins/ffmpeg/MuxerTable.cpp | 17 ++ src/add-ons/media/plugins/ffmpeg/config.h | 2 +- src/kits/media/EncoderPlugin.cpp | 56 ++++- src/kits/media/MediaTrack.cpp | 183 ++++++++++------ 10 files changed, 412 insertions(+), 137 deletions(-) diff --git a/headers/private/media/EncoderPlugin.h b/headers/private/media/EncoderPlugin.h index 7cba9a43a7..dabcdf1c1d 100644 --- a/headers/private/media/EncoderPlugin.h +++ b/headers/private/media/EncoderPlugin.h @@ -8,11 +8,10 @@ #include #include +#include #include "MediaPlugin.h" -class AddOnManager; - namespace BPrivate { namespace media { class PluginManager; @@ -56,10 +55,20 @@ public: virtual status_t AddTrackInfo(uint32 code, const void* data, size_t size, uint32 flags = 0); + // Ownership of the BView and BParameterWeb remain with the Encoder. + // A window embedding the view must remove it before it is destroyed. + virtual BView* ParameterView(); + + virtual BParameterWeb* ParameterWeb(); + virtual status_t GetParameterValue(int32 id, void* value, + size_t* size) const; + virtual status_t SetParameterValue(int32 id, const void* value, + size_t size); + virtual status_t GetEncodeParameters( encode_parameters* parameters) const; virtual status_t SetEncodeParameters( - encode_parameters* parameters) const; + encode_parameters* parameters); virtual status_t Encode(const void* buffer, int64 frameCount, media_encode_info* info) = 0; @@ -73,19 +82,36 @@ public: virtual status_t Perform(perform_code code, void* data); private: - virtual void _ReservedEncoder1(); - virtual void _ReservedEncoder2(); - virtual void _ReservedEncoder3(); - virtual void _ReservedEncoder4(); - virtual void _ReservedEncoder5(); - ChunkWriter* fChunkWriter; // needed for plug-in reference count management friend class PluginManager; MediaPlugin* fMediaPlugin; - uint32 fReserved[5]; +private: + // FBC padding + uint32 fReserved[20]; + + virtual void _ReservedEncoder1(); + virtual void _ReservedEncoder2(); + virtual void _ReservedEncoder3(); + virtual void _ReservedEncoder4(); + virtual void _ReservedEncoder5(); + virtual void _ReservedEncoder6(); + virtual void _ReservedEncoder7(); + virtual void _ReservedEncoder8(); + virtual void _ReservedEncoder9(); + virtual void _ReservedEncoder10(); + virtual void _ReservedEncoder11(); + virtual void _ReservedEncoder12(); + virtual void _ReservedEncoder13(); + virtual void _ReservedEncoder14(); + virtual void _ReservedEncoder15(); + virtual void _ReservedEncoder16(); + virtual void _ReservedEncoder17(); + virtual void _ReservedEncoder18(); + virtual void _ReservedEncoder19(); + virtual void _ReservedEncoder20(); }; diff --git a/src/add-ons/media/plugins/ffmpeg/AVCodecEncoder.cpp b/src/add-ons/media/plugins/ffmpeg/AVCodecEncoder.cpp index 0b0515bba8..43853188e1 100644 --- a/src/add-ons/media/plugins/ffmpeg/AVCodecEncoder.cpp +++ b/src/add-ons/media/plugins/ffmpeg/AVCodecEncoder.cpp @@ -30,12 +30,13 @@ extern "C" { static const size_t kDefaultChunkBufferSize = 2 * 1024 * 1024; -AVCodecEncoder::AVCodecEncoder(uint32 codecID) +AVCodecEncoder::AVCodecEncoder(uint32 codecID, int bitRateScale) : Encoder(), + fBitRateScale(bitRateScale), fCodec(NULL), fContext(avcodec_alloc_context()), - fCodecInitDone(false), + fCodecInitStatus(CODEC_INIT_NEEDED), fFrame(avcodec_alloc_frame()), fSwsContext(NULL), @@ -52,6 +53,11 @@ AVCodecEncoder::AVCodecEncoder(uint32 codecID) memset(&fInputFormat, 0, sizeof(media_format)); av_fifo_init(&fAudioFifo, 0); + + // Initial parameters, so we know if the user changed them + fEncodeParameters.avg_field_size = 0; + fEncodeParameters.max_field_size = 0; + fEncodeParameters.quality = 1.0f; } @@ -59,8 +65,7 @@ AVCodecEncoder::~AVCodecEncoder() { TRACE("AVCodecEncoder::~AVCodecEncoder()\n"); - if (fCodecInitDone) - avcodec_close(fContext); + _CloseCodecIfNeeded(); sws_freeContext(fSwsContext); @@ -119,15 +124,118 @@ AVCodecEncoder::SetUp(const media_format* inputFormat) if (inputFormat == NULL) return B_BAD_VALUE; - if (fCodecInitDone) { - fCodecInitDone = false; - avcodec_close(fContext); - } + _CloseCodecIfNeeded(); fInputFormat = *inputFormat; fFramesWritten = 0; + return _Setup(); +} + + +status_t +AVCodecEncoder::GetEncodeParameters(encode_parameters* parameters) const +{ + TRACE("AVCodecEncoder::GetEncodeParameters(%p)\n", parameters); + +// TODO: Implement maintaining an automatically calculated bit_rate versus +// a user specified (via SetEncodeParameters()) bit_rate. At this point, the +// fContext->bit_rate may not yet have been specified (_Setup() was never +// called yet). So it cannot work like the code below, but in any case, it's +// showing how to convert between the values (Albeit untested). +// int avgBytesPerSecond = fContext->bit_rate / 8; +// int maxBytesPerSecond = (fContext->bit_rate +// + fContext->bit_rate_tolerance) / 8; +// +// if (fInputFormat.type == B_MEDIA_RAW_AUDIO) { +// fEncodeParameters.avg_field_size = (int32)(avgBytesPerSecond +// / fInputFormat.u.raw_audio.frame_rate); +// fEncodeParameters.max_field_size = (int32)(maxBytesPerSecond +// / fInputFormat.u.raw_audio.frame_rate); +// } else if (fInputFormat.type == B_MEDIA_RAW_VIDEO) { +// fEncodeParameters.avg_field_size = (int32)(avgBytesPerSecond +// / fInputFormat.u.raw_video.field_rate); +// fEncodeParameters.max_field_size = (int32)(maxBytesPerSecond +// / fInputFormat.u.raw_video.field_rate); +// } + + parameters->quality = fEncodeParameters.quality; + + return B_OK; +} + + +status_t +AVCodecEncoder::SetEncodeParameters(encode_parameters* parameters) +{ + TRACE("AVCodecEncoder::SetEncodeParameters(%p)\n", parameters); + + if (fFramesWritten > 0) + return B_NOT_SUPPORTED; + + fEncodeParameters.quality = parameters->quality; + TRACE(" quality: %.1f\n", parameters->quality); + +// TODO: Auto-bit_rate versus user supplied. See above. +// int avgBytesPerSecond = 0; +// int maxBytesPerSecond = 0; +// +// if (fInputFormat.type == B_MEDIA_RAW_AUDIO) { +// avgBytesPerSecond = (int)(parameters->avg_field_size +// * fInputFormat.u.raw_audio.frame_rate); +// maxBytesPerSecond = (int)(parameters->max_field_size +// * fInputFormat.u.raw_audio.frame_rate); +// } else if (fInputFormat.type == B_MEDIA_RAW_VIDEO) { +// avgBytesPerSecond = (int)(parameters->avg_field_size +// * fInputFormat.u.raw_video.field_rate); +// maxBytesPerSecond = (int)(parameters->max_field_size +// * fInputFormat.u.raw_video.field_rate); +// } +// +// if (maxBytesPerSecond < avgBytesPerSecond) +// maxBytesPerSecond = avgBytesPerSecond; +// +// // Reset these, so we can tell the difference between uninitialized +// // and initialized... +// if (avgBytesPerSecond > 0) { +// fContext->bit_rate = avgBytesPerSecond * 8; +// fContext->bit_rate_tolerance = (maxBytesPerSecond +// - avgBytesPerSecond) * 8; +// fBitRateControlledByUser = true; +// } + + return _Setup(); +} + + +status_t +AVCodecEncoder::Encode(const void* buffer, int64 frameCount, + media_encode_info* info) +{ + TRACE("AVCodecEncoder::Encode(%p, %lld, %p)\n", buffer, frameCount, info); + + if (!_OpenCodecIfNeeded()) + return B_NO_INIT; + + if (fInputFormat.type == B_MEDIA_RAW_AUDIO) + return _EncodeAudio(buffer, frameCount, info); + else if (fInputFormat.type == B_MEDIA_RAW_VIDEO) + return _EncodeVideo(buffer, frameCount, info); + else + return B_NO_INIT; +} + + +// #pragma mark - + + +status_t +AVCodecEncoder::_Setup() +{ + TRACE("AVCodecEncoder::_Setup\n"); + if (fInputFormat.type == B_MEDIA_RAW_VIDEO) { + TRACE(" B_MEDIA_RAW_VIDEO\n"); // frame rate fContext->time_base.den = (int)fInputFormat.u.raw_video.field_rate; fContext->time_base.num = 1; @@ -144,7 +252,15 @@ AVCodecEncoder::SetUp(const media_format* inputFormat) // fContext->rc_max_rate = 0; // fContext->rc_min_rate = 0; // TODO: Try to calculate a good bit rate... - fContext->bit_rate = 800000; + int rawBitRate = (int)(fContext->width * fContext->height * 2 + * fInputFormat.u.raw_video.field_rate) * 8; + int wantedBitRate = (int)(rawBitRate / fBitRateScale + * fEncodeParameters.quality); + TRACE(" rawBitRate: %d, wantedBitRate: %d (%.1f)\n", rawBitRate, + wantedBitRate, fEncodeParameters.quality); + // TODO: Support letting the user overwrite this via + // SetEncodeParameters(). See comments there... + fContext->bit_rate = wantedBitRate; // Pixel aspect ratio fContext->sample_aspect_ratio.num @@ -188,6 +304,7 @@ AVCodecEncoder::SetUp(const media_format* inputFormat) fContext->pix_fmt, SWS_BICUBIC, NULL, NULL, NULL); } else if (fInputFormat.type == B_MEDIA_RAW_AUDIO) { + TRACE(" B_MEDIA_RAW_AUDIO\n"); // frame rate fContext->sample_rate = (int)fInputFormat.u.raw_audio.frame_rate; // NOTE: From the output_example.c, it looks like we are not supposed @@ -252,6 +369,7 @@ AVCodecEncoder::SetUp(const media_format* inputFormat) fContext->channel_layout = fInputFormat.u.raw_audio.channel_mask; } } else { + TRACE(" UNSUPPORTED MEDIA TYPE!\n"); return B_NOT_SUPPORTED; } @@ -266,55 +384,46 @@ AVCodecEncoder::SetUp(const media_format* inputFormat) fContext->mb_decision = 2; } + // Unfortunately, we may fail later, when we try to open the codec + // for real... but we need to delay this because we still allow + // parameter/quality changes. + return B_OK; +} + + +bool +AVCodecEncoder::_OpenCodecIfNeeded() +{ + if (fCodecInitStatus == CODEC_INIT_DONE) + return true; + + if (fCodecInitStatus == CODEC_INIT_FAILED) + return false; + // Open the codec int result = avcodec_open(fContext, fCodec); - fCodecInitDone = (result >= 0); + if (result >= 0) + fCodecInitStatus = CODEC_INIT_DONE; + else + fCodecInitStatus = CODEC_INIT_FAILED; TRACE(" avcodec_open(): %d\n", result); - return fCodecInitDone ? B_OK : B_ERROR; + return fCodecInitStatus == CODEC_INIT_DONE; + } -status_t -AVCodecEncoder::GetEncodeParameters(encode_parameters* parameters) const +void +AVCodecEncoder::_CloseCodecIfNeeded() { - TRACE("AVCodecEncoder::GetEncodeParameters(%p)\n", parameters); - - return B_NOT_SUPPORTED; + if (fCodecInitStatus == CODEC_INIT_DONE) { + avcodec_close(fContext); + fCodecInitStatus = CODEC_INIT_NEEDED; + } } -status_t -AVCodecEncoder::SetEncodeParameters(encode_parameters* parameters) const -{ - TRACE("AVCodecEncoder::SetEncodeParameters(%p)\n", parameters); - - return B_NOT_SUPPORTED; -} - - -status_t -AVCodecEncoder::Encode(const void* buffer, int64 frameCount, - media_encode_info* info) -{ - TRACE("AVCodecEncoder::Encode(%p, %lld, %p)\n", buffer, frameCount, info); - - if (!fCodecInitDone) - return B_NO_INIT; - - if (fInputFormat.type == B_MEDIA_RAW_AUDIO) - return _EncodeAudio(buffer, frameCount, info); - else if (fInputFormat.type == B_MEDIA_RAW_VIDEO) - return _EncodeVideo(buffer, frameCount, info); - else - return B_NO_INIT; -} - - -// #pragma mark - - - static const int64 kNoPTSValue = 0x8000000000000000LL; // NOTE: For some reasons, I have trouble with the avcodec.h define: // #define AV_NOPTS_VALUE INT64_C(0x8000000000000000) diff --git a/src/add-ons/media/plugins/ffmpeg/AVCodecEncoder.h b/src/add-ons/media/plugins/ffmpeg/AVCodecEncoder.h index 3936eb77db..dca46b5691 100644 --- a/src/add-ons/media/plugins/ffmpeg/AVCodecEncoder.h +++ b/src/add-ons/media/plugins/ffmpeg/AVCodecEncoder.h @@ -19,7 +19,8 @@ extern "C" { class AVCodecEncoder : public Encoder { public: - AVCodecEncoder(uint32 codecID); + AVCodecEncoder(uint32 codecID, + int bitRateScale); virtual ~AVCodecEncoder(); @@ -32,7 +33,7 @@ public: virtual status_t GetEncodeParameters( encode_parameters* parameters) const; virtual status_t SetEncodeParameters( - encode_parameters* parameters) const; + encode_parameters* parameters); virtual status_t Encode(const void* buffer, int64 frameCount, media_encode_info* info); @@ -42,6 +43,11 @@ public: // codec buffer size. private: + status_t _Setup(); + + bool _OpenCodecIfNeeded(); + void _CloseCodecIfNeeded(); + status_t _EncodeAudio(const void* buffer, int64 frameCount, media_encode_info* info); @@ -55,12 +61,20 @@ private: private: media_format fInputFormat; + encode_parameters fEncodeParameters; + int fBitRateScale; // FFmpeg related members // TODO: Refactor common base class from AVCodec[De|En]Coder! AVCodec* fCodec; AVCodecContext* fContext; - bool fCodecInitDone; + + enum { + CODEC_INIT_NEEDED = 0, + CODEC_INIT_DONE, + CODEC_INIT_FAILED + }; + uint32 fCodecInitStatus; // For video (color space conversion): AVPicture fSrcFrame; diff --git a/src/add-ons/media/plugins/ffmpeg/EncoderTable.cpp b/src/add-ons/media/plugins/ffmpeg/EncoderTable.cpp index 5bdf8aae14..e6770dbe2b 100644 --- a/src/add-ons/media/plugins/ffmpeg/EncoderTable.cpp +++ b/src/add-ons/media/plugins/ffmpeg/EncoderTable.cpp @@ -22,7 +22,8 @@ const EncoderDescription gEncoderTable[] = { }, B_ANY_FORMAT_FAMILY, // TODO: Hm, actually not really /any/ family... B_MEDIA_RAW_VIDEO, - B_MEDIA_ENCODED_VIDEO + B_MEDIA_ENCODED_VIDEO, + 23 }, { { @@ -34,7 +35,8 @@ const EncoderDescription gEncoderTable[] = { }, B_MPEG_FORMAT_FAMILY, B_MEDIA_RAW_VIDEO, - B_MEDIA_ENCODED_VIDEO + B_MEDIA_ENCODED_VIDEO, + 10 }, { { @@ -46,7 +48,8 @@ const EncoderDescription gEncoderTable[] = { }, B_MPEG_FORMAT_FAMILY, B_MEDIA_RAW_VIDEO, - B_MEDIA_ENCODED_VIDEO + B_MEDIA_ENCODED_VIDEO, + 15 }, { { @@ -58,7 +61,8 @@ const EncoderDescription gEncoderTable[] = { }, B_ANY_FORMAT_FAMILY, B_MEDIA_RAW_AUDIO, - B_MEDIA_ENCODED_AUDIO + B_MEDIA_ENCODED_AUDIO, + 1 }, { { @@ -70,7 +74,8 @@ const EncoderDescription gEncoderTable[] = { }, B_ANY_FORMAT_FAMILY, B_MEDIA_RAW_AUDIO, - B_MEDIA_ENCODED_AUDIO + B_MEDIA_ENCODED_AUDIO, + 10 } }; diff --git a/src/add-ons/media/plugins/ffmpeg/EncoderTable.h b/src/add-ons/media/plugins/ffmpeg/EncoderTable.h index 9083b6bfb1..2f3a9e7a9b 100644 --- a/src/add-ons/media/plugins/ffmpeg/EncoderTable.h +++ b/src/add-ons/media/plugins/ffmpeg/EncoderTable.h @@ -14,6 +14,7 @@ struct EncoderDescription { media_format_family format_family; media_type input_type; media_type output_type; + int bit_rate_scale; }; diff --git a/src/add-ons/media/plugins/ffmpeg/FFmpegPlugin.cpp b/src/add-ons/media/plugins/ffmpeg/FFmpegPlugin.cpp index 39cedb7741..3e4e1bb5ee 100644 --- a/src/add-ons/media/plugins/ffmpeg/FFmpegPlugin.cpp +++ b/src/add-ons/media/plugins/ffmpeg/FFmpegPlugin.cpp @@ -134,7 +134,13 @@ FFmpegPlugin::GetSupportedFileFormats(const media_file_format** _fileFormats, Encoder* FFmpegPlugin::NewEncoder(const media_codec_info& codecInfo) { - return new(std::nothrow)AVCodecEncoder(codecInfo.sub_id); + for (size_t i = 0; i < gEncoderCount; i++) { + if (codecInfo.sub_id == gEncoderTable[i].codec_info.sub_id) { + return new(std::nothrow)AVCodecEncoder(codecInfo.sub_id, + gEncoderTable[i].bit_rate_scale); + } + } + return NULL; } diff --git a/src/add-ons/media/plugins/ffmpeg/MuxerTable.cpp b/src/add-ons/media/plugins/ffmpeg/MuxerTable.cpp index ecb0e9f180..827e5ca3c5 100644 --- a/src/add-ons/media/plugins/ffmpeg/MuxerTable.cpp +++ b/src/add-ons/media/plugins/ffmpeg/MuxerTable.cpp @@ -38,6 +38,23 @@ const media_file_format gMuxerTable[] = { "mpg", { 0 } }, +// TODO: This one rejects unknown codecs. We probably need to define +// a media_format_family for it so that Encoders can announce their support +// for it specifically. +// { +// media_file_format::B_WRITABLE +// | media_file_format::B_KNOWS_ENCODED_VIDEO +// | media_file_format::B_KNOWS_ENCODED_AUDIO, +// { 0 }, +// B_AVI_FORMAT_FAMILY, +// 100, +// { 0 }, +// "application/ogg", +// "Ogg (Xiph.Org Foundation)", +// "ogg", +// "ogg", +// { 0 } +// }, }; const size_t gMuxerCount = sizeof(gMuxerTable) / sizeof(media_file_format); diff --git a/src/add-ons/media/plugins/ffmpeg/config.h b/src/add-ons/media/plugins/ffmpeg/config.h index 21a53b6f84..223d512fa4 100644 --- a/src/add-ons/media/plugins/ffmpeg/config.h +++ b/src/add-ons/media/plugins/ffmpeg/config.h @@ -686,7 +686,7 @@ #define CONFIG_MXF_D10_MUXER 0 #define CONFIG_NULL_MUXER 0 #define CONFIG_NUT_MUXER 0 -#define CONFIG_OGG_MUXER 0 +#define CONFIG_OGG_MUXER 1 #define CONFIG_PCM_ALAW_MUXER 0 #define CONFIG_PCM_MULAW_MUXER 0 #define CONFIG_PCM_F64BE_MUXER 0 diff --git a/src/kits/media/EncoderPlugin.cpp b/src/kits/media/EncoderPlugin.cpp index dd0b3462cc..8851feb032 100644 --- a/src/kits/media/EncoderPlugin.cpp +++ b/src/kits/media/EncoderPlugin.cpp @@ -26,6 +26,9 @@ Encoder::~Encoder() } +// #pragma mark - Convenience stubs + + status_t Encoder::AddTrackInfo(uint32 code, const void* data, size_t size, uint32 flags) { @@ -33,6 +36,34 @@ Encoder::AddTrackInfo(uint32 code, const void* data, size_t size, uint32 flags) } +BView* +Encoder::ParameterView() +{ + return NULL; +} + + +BParameterWeb* +Encoder::ParameterWeb() +{ + return NULL; +} + + +status_t +Encoder::GetParameterValue(int32 id, void* value, size_t* size) const +{ + return B_NOT_SUPPORTED; +} + + +status_t +Encoder::SetParameterValue(int32 id, const void* value, size_t size) +{ + return B_NOT_SUPPORTED; +} + + status_t Encoder::GetEncodeParameters(encode_parameters* parameters) const { @@ -41,12 +72,15 @@ Encoder::GetEncodeParameters(encode_parameters* parameters) const status_t -Encoder::SetEncodeParameters(encode_parameters* parameters) const +Encoder::SetEncodeParameters(encode_parameters* parameters) { return B_NOT_SUPPORTED; } +// #pragma mark - + + status_t Encoder::WriteChunk(const void* chunkBuffer, size_t chunkSize, media_encode_info* encodeInfo) @@ -63,6 +97,9 @@ Encoder::SetChunkWriter(ChunkWriter* writer) } +// #pragma mark - FBC padding + + status_t Encoder::Perform(perform_code code, void* data) { @@ -75,9 +112,24 @@ void Encoder::_ReservedEncoder2() {} void Encoder::_ReservedEncoder3() {} void Encoder::_ReservedEncoder4() {} void Encoder::_ReservedEncoder5() {} +void Encoder::_ReservedEncoder6() {} +void Encoder::_ReservedEncoder7() {} +void Encoder::_ReservedEncoder8() {} +void Encoder::_ReservedEncoder9() {} +void Encoder::_ReservedEncoder10() {} +void Encoder::_ReservedEncoder11() {} +void Encoder::_ReservedEncoder12() {} +void Encoder::_ReservedEncoder13() {} +void Encoder::_ReservedEncoder14() {} +void Encoder::_ReservedEncoder15() {} +void Encoder::_ReservedEncoder16() {} +void Encoder::_ReservedEncoder17() {} +void Encoder::_ReservedEncoder18() {} +void Encoder::_ReservedEncoder19() {} +void Encoder::_ReservedEncoder20() {} -// #pragma mark - +// #pragma mark - EncoderPlugin EncoderPlugin::EncoderPlugin() diff --git a/src/kits/media/MediaTrack.cpp b/src/kits/media/MediaTrack.cpp index 637758f6a8..0ecc835835 100644 --- a/src/kits/media/MediaTrack.cpp +++ b/src/kits/media/MediaTrack.cpp @@ -76,6 +76,7 @@ BMediaTrack::~BMediaTrack() CALLED(); _plugin_manager.DestroyDecoder(fRawDecoder); _plugin_manager.DestroyDecoder(fDecoder); + _plugin_manager.DestroyDecoder(fEncoder); } /************************************************************* @@ -321,28 +322,31 @@ BMediaTrack::ReadFrames(void *out_buffer, status_t -BMediaTrack::ReplaceFrames(const void *in_buffer, - int64 *io_frameCount, - const media_header *mh) +BMediaTrack::ReplaceFrames(const void* inBuffer, int64* inOutFrameCount, + const media_header* mediaHeader) { UNIMPLEMENTED(); - return B_OK; + // TODO: Actually, a file is either open for reading or writing at the + // moment. Since the chunk size of encoded media data will change, + // implementing this call will only be possible for raw media tracks. + + return B_NOT_SUPPORTED; } status_t -BMediaTrack::SeekToTime(bigtime_t *inout_time, int32 flags) +BMediaTrack::SeekToTime(bigtime_t* inOutTime, int32 flags) { CALLED(); if (!fDecoder || !fExtractor) return B_NO_INIT; - if (!inout_time) + if (!inOutTime) return B_BAD_VALUE; uint32 seekTo = (flags & B_MEDIA_SEEK_DIRECTION_MASK) | B_MEDIA_SEEK_TO_TIME; - bigtime_t seekTime = *inout_time; + bigtime_t seekTime = *inOutTime; int64 frame = 0; bigtime_t time = seekTime; @@ -355,7 +359,7 @@ BMediaTrack::SeekToTime(bigtime_t *inout_time, int32 flags) // TODO: Codecs cannot actually "seek" in the stream, all they // can do is "reset" their decoder state, since they are made // aware of the fact that there will be a jump in the data. Maybe - // rename the codec method? + // rename the Decoder method? result = fDecoder->Seek(seekTo, 0, &frame, seekTime, &time); if (result != B_OK) { ERROR("BMediaTrack::SeekToTime: decoder seek failed\n"); @@ -370,11 +374,12 @@ BMediaTrack::SeekToTime(bigtime_t *inout_time, int32 flags) } } - *inout_time = time; + *inOutTime = time; fCurFrame = frame; fCurTime = time; - PRINT(1, "BMediaTrack::SeekToTime finished, requested %.6f, result %.6f\n", seekTime / 1000000.0, *inout_time / 1000000.0); + PRINT(1, "BMediaTrack::SeekToTime finished, requested %.6f, result %.6f\n", + seekTime / 1000000.0, *inOutTime / 1000000.0); return B_OK; } @@ -589,102 +594,142 @@ BMediaTrack::Flush() BParameterWeb* BMediaTrack::Web() { - UNIMPLEMENTED(); + BParameterWeb* web; + if (GetParameterWeb(&web) == B_OK) + return web; return NULL; } -// returns a copy of the parameter web status_t BMediaTrack::GetParameterWeb(BParameterWeb** outWeb) { - UNIMPLEMENTED(); + if (outWeb == NULL) + return B_BAD_VALUE; + + if (fEncoder == NULL) + return B_NO_INIT; + + // TODO: This method is new in Haiku. The header mentions it returns a + // copy. But how could it even do that? How can one clone a web and make + // it point to the same BControllable? + *outWeb = fEncoder->ParameterWeb(); + if (*outWeb != NULL) + return B_OK; + + return B_NOT_SUPPORTED; +} + + +status_t +BMediaTrack::GetParameterValue(int32 id, void* value, size_t* size) +{ + if (value == NULL || size == NULL) + return B_BAD_VALUE; + + if (fEncoder == NULL) + return B_NO_INIT; + + return fEncoder->GetParameterValue(id, value, size); +} + + +status_t +BMediaTrack::SetParameterValue(int32 id, const void* value, size_t size) +{ + if (value == NULL || size == 0) + return B_BAD_VALUE; + + if (fEncoder == NULL) + return B_NO_INIT; + + return fEncoder->SetParameterValue(id, value, size); +} + + +BView* +BMediaTrack::GetParameterView() +{ + if (fEncoder == NULL) + return NULL; + + return fEncoder->ParameterView(); +} + + +status_t +BMediaTrack::GetQuality(float* quality) +{ + if (quality == NULL) + return B_BAD_VALUE; + + encode_parameters parameters; + status_t ret = GetEncodeParameters(¶meters); + if (ret != B_OK) + return ret; + + *quality = parameters.quality; return B_OK; } -status_t -BMediaTrack::GetParameterValue(int32 id, - void *valu, - size_t *size) -{ - UNIMPLEMENTED(); - - return B_ERROR; -} - - -status_t -BMediaTrack::SetParameterValue(int32 id, - const void *valu, - size_t size) -{ - UNIMPLEMENTED(); - - return B_ERROR; -} - - -BView * -BMediaTrack::GetParameterView() -{ - UNIMPLEMENTED(); - return NULL; -} - - -status_t -BMediaTrack::GetQuality(float *quality) -{ - UNIMPLEMENTED(); - - return B_ERROR; -} - - status_t BMediaTrack::SetQuality(float quality) { - UNIMPLEMENTED(); + encode_parameters parameters; + status_t ret = GetEncodeParameters(¶meters); + if (ret != B_OK) + return ret; - return B_ERROR; + if (quality < 0.0f) + quality = 0.0f; + if (quality > 1.0f) + quality = 1.0f; + + parameters.quality = quality; + + return SetEncodeParameters(¶meters); } status_t -BMediaTrack::GetEncodeParameters(encode_parameters *parameters) const +BMediaTrack::GetEncodeParameters(encode_parameters* parameters) const { - UNIMPLEMENTED(); + if (parameters == NULL) + return B_BAD_VALUE; - return B_ERROR; + if (fEncoder == NULL) + return B_NO_INIT; + + return fEncoder->GetEncodeParameters(parameters); } status_t BMediaTrack::SetEncodeParameters(encode_parameters *parameters) { - UNIMPLEMENTED(); + if (parameters == NULL) + return B_BAD_VALUE; - return B_ERROR; + if (fEncoder == NULL) + return B_NO_INIT; + + return fEncoder->SetEncodeParameters(parameters); } status_t -BMediaTrack::Perform(int32 selector, - void *data) +BMediaTrack::Perform(int32 selector, void* data) { - UNIMPLEMENTED(); - - return B_ERROR; + return B_OK; } -/************************************************************* - * private BMediaTrack - *************************************************************/ +// #pragma mark - private -BMediaTrack::BMediaTrack(BPrivate::media::MediaExtractor *extractor, - int32 stream) + +BMediaTrack::BMediaTrack(BPrivate::media::MediaExtractor* extractor, + int32 stream) { CALLED(); fWorkaroundFlags = 0;