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:
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user