From 6033e52a8318c9f9b1a6945709fe89b0d070471b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stephan=20A=C3=9Fmus?= Date: Fri, 31 Jul 2009 00:46:36 +0000 Subject: [PATCH] Implemented support for get_next_encoder() variations from MediaFormats.h. The AddOnManager in the media_server registers one encoder entry per successful EncoderPlugin::RegisterNextEncoder(). This gives us a first idea what media_format_family and input/output media_type is supported. The mechanism may have to be extended, or the Encoder needs an API to specialize a format further. In that case, the get_next_encoder() version that takes optional _acceptedInput/OutputFormat needs to instantiate the plugin and needs to ask the Encoder. But AFAIK, no app uses it like that anyway. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@32005 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- headers/private/media/DataExchange.h | 13 +++ headers/private/media/EncoderPlugin.h | 23 ++-- .../media/plugins/ffmpeg/EncoderTable.cpp | 36 +++--- .../media/plugins/ffmpeg/EncoderTable.h | 10 +- .../media/plugins/ffmpeg/FFmpegPlugin.cpp | 17 ++- .../media/plugins/ffmpeg/FFmpegPlugin.h | 8 +- src/kits/media/MediaFormats.cpp | 104 ++++++++++++++++-- src/servers/media/AddOnManager.cpp | 59 +++++++--- src/servers/media/AddOnManager.h | 9 +- src/servers/media/media_server.cpp | 13 +++ 10 files changed, 232 insertions(+), 60 deletions(-) diff --git a/headers/private/media/DataExchange.h b/headers/private/media/DataExchange.h index 736e984466..6a7f1ab90d 100644 --- a/headers/private/media/DataExchange.h +++ b/headers/private/media/DataExchange.h @@ -133,6 +133,7 @@ enum { SERVER_GET_DECODER_FOR_FORMAT, SERVER_GET_WRITER_FOR_FORMAT_FAMILY, SERVER_GET_FILE_FORMAT_FOR_COOKIE, + SERVER_GET_CODEC_INFO_FOR_COOKIE, SERVER_GET_ENCODER_FOR_CODEC_INFO, SERVER_MESSAGE_END, NODE_MESSAGE_START = 0x200, @@ -844,6 +845,18 @@ struct server_get_file_format_reply : reply_data { // the file format matching the cookie }; +struct server_get_codec_info_request : request_data { + int32 cookie; +}; + +struct server_get_codec_info_reply : reply_data { + media_codec_info codec_info; + media_format_family format_family; + media_format input_format; + media_format output_format; + // the codec info matching the cookie +}; + struct node_request_completed_command : command_data { media_request_info info; }; diff --git a/headers/private/media/EncoderPlugin.h b/headers/private/media/EncoderPlugin.h index cb19f238c9..8aaa2b9003 100644 --- a/headers/private/media/EncoderPlugin.h +++ b/headers/private/media/EncoderPlugin.h @@ -30,6 +30,13 @@ public: Encoder(); virtual ~Encoder(); + // TODO: I think we may actually need a method to specialize a + // media_format. For example, some codecs may only support certain + // input color spaces, or output color spaces, or multiple of 16 + // width/height... This support is technically even needed for + // MediaFormats.h functionality, although there probably isn't + // an application out there which uses it like that. + virtual status_t SetFormat(const media_file_format& fileFormat, media_format* _inOutEncodedFormat) = 0; @@ -75,17 +82,11 @@ public: virtual Encoder* NewEncoder( const media_codec_info& codecInfo) = 0; - // TODO: Maybe this also needs to return a media_format with wild cards - // so that we can support the respective get_next_encoder() functions - // that take media_formats with wild cards and specialize them. - // Then this interface could be turned into an iterator like interface: - // - // status_t GetNextSupportedCodec(int32* cookie, - // const media_codec_info* codecInfo, - // const media_format* format) = 0; - virtual status_t GetSupportedCodecs( - const media_codec_info** codecInfos, - size_t* count) = 0; + virtual status_t RegisterNextEncoder(int32* cookie, + media_codec_info* codecInfo, + media_format_family* formatFamily, + media_format* inputFormat, + media_format* outputFormat) = 0; }; } } // namespace BPrivate::media diff --git a/src/add-ons/media/plugins/ffmpeg/EncoderTable.cpp b/src/add-ons/media/plugins/ffmpeg/EncoderTable.cpp index bf03bb5844..2b18ac2931 100644 --- a/src/add-ons/media/plugins/ffmpeg/EncoderTable.cpp +++ b/src/add-ons/media/plugins/ffmpeg/EncoderTable.cpp @@ -7,22 +7,32 @@ #include "EncoderTable.h" -const media_codec_info gEncoderTable[] = { +const EncoderDescription gEncoderTable[] = { { - "MPEG2 Video", - "mpeg2video", - 0, - 0, - { 0 } + { + "MPEG2 Video", + "mpeg2video", + 0, + 0, + { 0 } + }, + B_ANY_FORMAT_FAMILY, + B_MEDIA_RAW_VIDEO, + B_MEDIA_ENCODED_VIDEO }, { - "WAV", - "wav", - 0, - 0, - { 0 } - }, + { + "WAV", + "wav", + 0, + 0, + { 0 } + }, + B_ANY_FORMAT_FAMILY, + B_MEDIA_RAW_AUDIO, + B_MEDIA_ENCODED_AUDIO + } }; -const size_t gEncoderCount = sizeof(gEncoderTable) / sizeof(media_codec_info); +const size_t gEncoderCount = sizeof(gEncoderTable) / sizeof(EncoderDescription); diff --git a/src/add-ons/media/plugins/ffmpeg/EncoderTable.h b/src/add-ons/media/plugins/ffmpeg/EncoderTable.h index 476f09488d..9083b6bfb1 100644 --- a/src/add-ons/media/plugins/ffmpeg/EncoderTable.h +++ b/src/add-ons/media/plugins/ffmpeg/EncoderTable.h @@ -9,7 +9,15 @@ #include -extern const media_codec_info gEncoderTable[]; +struct EncoderDescription { + media_codec_info codec_info; + media_format_family format_family; + media_type input_type; + media_type output_type; +}; + + +extern const EncoderDescription gEncoderTable[]; extern const size_t gEncoderCount; diff --git a/src/add-ons/media/plugins/ffmpeg/FFmpegPlugin.cpp b/src/add-ons/media/plugins/ffmpeg/FFmpegPlugin.cpp index a1632e5c73..cf531998cb 100644 --- a/src/add-ons/media/plugins/ffmpeg/FFmpegPlugin.cpp +++ b/src/add-ons/media/plugins/ffmpeg/FFmpegPlugin.cpp @@ -139,11 +139,20 @@ FFmpegPlugin::NewEncoder(const media_codec_info& codecInfo) status_t -FFmpegPlugin::GetSupportedCodecs(const media_codec_info** _codecInfos, - size_t* _count) +FFmpegPlugin::RegisterNextEncoder(int32* cookie, media_codec_info* _codecInfo, + media_format_family* _formatFamily, media_format* _inputFormat, + media_format* _outputFormat) { - *_codecInfos = gEncoderTable; - *_count = gEncoderCount; + if (*cookie < 0 || *cookie >= (int32)gEncoderCount) + return B_BAD_INDEX; + + *_codecInfo = gEncoderTable[*cookie].codec_info; + *_formatFamily = gEncoderTable[*cookie].format_family; + _inputFormat->type = gEncoderTable[*cookie].input_type; + _outputFormat->type = gEncoderTable[*cookie].output_type;; + + *cookie = *cookie + 1; + return B_OK; } diff --git a/src/add-ons/media/plugins/ffmpeg/FFmpegPlugin.h b/src/add-ons/media/plugins/ffmpeg/FFmpegPlugin.h index b770f70a67..ef37a5fd75 100644 --- a/src/add-ons/media/plugins/ffmpeg/FFmpegPlugin.h +++ b/src/add-ons/media/plugins/ffmpeg/FFmpegPlugin.h @@ -34,9 +34,11 @@ public: virtual Encoder* NewEncoder( const media_codec_info& codecInfo); - virtual status_t GetSupportedCodecs( - const media_codec_info** codecInfos, - size_t* count); + virtual status_t RegisterNextEncoder(int32* cookie, + media_codec_info* codecInfo, + media_format_family* formatFamily, + media_format* inputFormat, + media_format* outputFormat); private: class GlobalInitilizer { diff --git a/src/kits/media/MediaFormats.cpp b/src/kits/media/MediaFormats.cpp index 47b8b5e99e..7114b4f8bb 100644 --- a/src/kits/media/MediaFormats.cpp +++ b/src/kits/media/MediaFormats.cpp @@ -28,31 +28,115 @@ static bigtime_t sLastFormatsUpdate; status_t -get_next_encoder(int32* cookie, const media_file_format* _fileFormat, - const media_format* inFormat, media_format* _outFormat, +get_next_encoder(int32* cookie, const media_file_format* fileFormat, + const media_format* inputFormat, media_format* _outputFormat, media_codec_info* _codecInfo) { - UNIMPLEMENTED(); - return B_ERROR; + // TODO: If fileFormat is provided (existing apps also pass NULL), + // we could at least check fileFormat->capabilities against + // outputFormat->type without even contacting the server. + + if (cookie == NULL || inputFormat == NULL || _codecInfo == NULL) + return B_BAD_VALUE; + + while (true) { + server_get_codec_info_request request; + request.cookie = *cookie; + server_get_codec_info_reply reply; + status_t ret = QueryServer(SERVER_GET_CODEC_INFO_FOR_COOKIE, &request, + sizeof(request), &reply, sizeof(reply)); + if (ret != B_OK) + return ret; + + *cookie = *cookie + 1; + + if (fileFormat != NULL && fileFormat->family != reply.format_family) + continue; + + if (!reply.input_format.Matches(inputFormat)) + continue; + + if (_outputFormat != NULL) + *_outputFormat = reply.output_format; + + *_codecInfo = reply.codec_info; + break; + } + + return B_OK; } status_t -get_next_encoder(int32* cookie, const media_file_format* _fileFormat, - const media_format* inFormat, const media_format* _outFormat, +get_next_encoder(int32* cookie, const media_file_format* fileFormat, + const media_format* inputFormat, const media_format* outputFormat, media_codec_info* _codecInfo, media_format* _acceptedInputFormat, media_format* _acceptedOutputFormat) { - UNIMPLEMENTED(); - return B_ERROR; + // TODO: If fileFormat is provided (existing apps also pass NULL), + // we could at least check fileFormat->capabilities against + // outputFormat->type without even contacting the server. + + if (cookie == NULL || inputFormat == NULL || outputFormat == NULL + || _codecInfo == NULL) { + return B_BAD_VALUE; + } + + while (true) { + server_get_codec_info_request request; + request.cookie = *cookie; + server_get_codec_info_reply reply; + status_t ret = QueryServer(SERVER_GET_CODEC_INFO_FOR_COOKIE, &request, + sizeof(request), &reply, sizeof(reply)); + if (ret != B_OK) + return ret; + + *cookie = *cookie + 1; + + if (fileFormat != NULL && fileFormat->family != reply.format_family) + continue; + + if (!reply.input_format.Matches(inputFormat) + || !reply.output_format.Matches(outputFormat)) { + continue; + } + + // TODO: These formats are currently way too generic. For example, + // an encoder may want to adjust video width to a multiple of 16, + // or overwrite the intput and or output color space. To make this + // possible, we actually have to instantiate an Encoder here and + // ask it to specifiy the format. + if (_acceptedInputFormat != NULL) + *_acceptedInputFormat = reply.input_format; + if (_acceptedOutputFormat != NULL) + *_acceptedOutputFormat = reply.output_format; + + *_codecInfo = reply.codec_info; + break; + } + + return B_OK; } status_t get_next_encoder(int32* cookie, media_codec_info* _codecInfo) { - UNIMPLEMENTED(); - return B_ERROR; + if (cookie == NULL || _codecInfo == NULL) + return B_BAD_VALUE; + + server_get_codec_info_request request; + request.cookie = *cookie; + server_get_codec_info_reply reply; + status_t ret = QueryServer(SERVER_GET_CODEC_INFO_FOR_COOKIE, &request, + sizeof(request), &reply, sizeof(reply)); + if (ret != B_OK) + return ret; + + *cookie = *cookie + 1; + *_codecInfo = reply.codec_info; + + return B_OK; } diff --git a/src/servers/media/AddOnManager.cpp b/src/servers/media/AddOnManager.cpp index e9dfe4288f..a9c18086d9 100644 --- a/src/servers/media/AddOnManager.cpp +++ b/src/servers/media/AddOnManager.cpp @@ -149,7 +149,7 @@ AddOnManager::GetEncoder(xfer_entry_ref* _encoderRef, int32 id) encoder_info* info; for (fEncoderList.Rewind(); fEncoderList.GetNext(&info);) { // check if the encoder matches the supplied format - if (info->internalID == id) { + if (info->internalID == (uint32)id) { printf("AddOnManager::GetEncoderForFormat: found encoder %s for " "id %ld\n", info->ref.name, id); @@ -200,6 +200,26 @@ AddOnManager::GetFileFormat(media_file_format* _fileFormat, int32 cookie) } +status_t +AddOnManager::GetCodecInfo(media_codec_info* _codecInfo, + media_format_family* _formatFamily, + media_format* _inputFormat, media_format* _outputFormat, int32 cookie) +{ + BAutolock locker(fLock); + + encoder_info* info; + if (fEncoderList.Get(cookie, &info)) { + *_codecInfo = info->codecInfo; + *_formatFamily = info->formatFamily; + *_inputFormat = info->intputFormat; + *_outputFormat = info->outputFormat; + return B_OK; + } + + return B_BAD_INDEX; +} + + // #pragma mark - @@ -439,34 +459,39 @@ AddOnManager::_RegisterEncoder(EncoderPlugin* plugin, const entry_ref& ref) encoder_info* pinfo; for (fEncoderList.Rewind(); fEncoderList.GetNext(&pinfo);) { if (!strcmp(pinfo->ref.name, ref.name)) { - // we already know this encoder + // We already know this encoder. When we reject encoders with + // the same name, we allow the user to overwrite system encoders + // in her home folder. return; } } printf("AddOnManager::_RegisterEncoder, name %s\n", ref.name); + // Get list of supported encoders... + encoder_info info; info.ref = ref; info.internalID = fNextEncoderCodecInfoID++; - // Get list of supported codecs... - const media_codec_info* codecInfos = NULL; - size_t count = 0; - if (plugin->GetSupportedCodecs(&codecInfos, &count) != B_OK) { - printf("AddOnManager::_RegisterEncoder(): plugin->GetSupportedCodecs" - "(...) failed!\n"); - return; - } + int32 cookie = 0; + int32 subID = 0; - for (uint32 i = 0 ; i < count ; i++) { - media_codec_info codecInfo = codecInfos[i]; - codecInfo.id = info.internalID; - codecInfo.sub_id = i; - info.codecInfos.Insert(codecInfo); - } + while (true) { + memset(&info.codecInfo, 0, sizeof(media_codec_info)); + memset(&info.intputFormat, 0, sizeof(media_format)); + memset(&info.outputFormat, 0, sizeof(media_format)); + if (plugin->RegisterNextEncoder(&cookie, + &info.codecInfo, &info.formatFamily, &info.intputFormat, + &info.outputFormat) != B_OK) { + break; + } + info.codecInfo.id = info.internalID; + info.codecInfo.sub_id = subID++; - fEncoderList.Insert(info); + if (!fEncoderList.Insert(info)) + break; + } } diff --git a/src/servers/media/AddOnManager.h b/src/servers/media/AddOnManager.h index b7704b953e..d2f55b97ad 100644 --- a/src/servers/media/AddOnManager.h +++ b/src/servers/media/AddOnManager.h @@ -48,6 +48,10 @@ public: status_t GetFileFormat(media_file_format* _fileFormat, int32 cookie); + status_t GetCodecInfo(media_codec_info* _codecInfo, + media_format_family* _formatFamily, + media_format* _inputFormat, + media_format* _outputFormat, int32 cookie); private: status_t _RegisterAddOn(BEntry& entry); @@ -78,7 +82,10 @@ private: struct encoder_info { entry_ref ref; uint32 internalID; - List codecInfos; + media_codec_info codecInfo; + media_format_family formatFamily; + media_format intputFormat; + media_format outputFormat; }; BLocker fLock; diff --git a/src/servers/media/media_server.cpp b/src/servers/media/media_server.cpp index fdc436dec4..7c789b545b 100644 --- a/src/servers/media/media_server.cpp +++ b/src/servers/media/media_server.cpp @@ -908,6 +908,19 @@ ServerApp::HandleMessage(int32 code, void *data, size_t size) break; } + case SERVER_GET_CODEC_INFO_FOR_COOKIE: + { + const server_get_codec_info_request *request + = reinterpret_cast< + const server_get_codec_info_request *>(data); + server_get_codec_info_reply reply; + rv = gAddOnManager->GetCodecInfo(&reply.codec_info, + &reply.format_family, &reply.input_format, + &reply.output_format, request->cookie); + request->SendReply(rv, &reply, sizeof(reply)); + break; + } + case SERVER_GET_ENCODER_FOR_CODEC_INFO: { const server_get_encoder_for_codec_info_request *request