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
This commit is contained in:
Stephan Aßmus
2009-07-31 00:46:36 +00:00
parent 061d2ed1a2
commit 6033e52a83
10 changed files with 232 additions and 60 deletions
+13
View File
@@ -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;
};
+12 -11
View File
@@ -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
@@ -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);
@@ -9,7 +9,15 @@
#include <MediaFormats.h>
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;
@@ -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;
}
@@ -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 {
+94 -10
View File
@@ -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;
}
+42 -17
View File
@@ -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;
}
}
+8 -1
View File
@@ -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<media_codec_info> codecInfos;
media_codec_info codecInfo;
media_format_family formatFamily;
media_format intputFormat;
media_format outputFormat;
};
BLocker fLock;
+13
View File
@@ -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