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_DECODER_FOR_FORMAT,
|
||||||
SERVER_GET_WRITER_FOR_FORMAT_FAMILY,
|
SERVER_GET_WRITER_FOR_FORMAT_FAMILY,
|
||||||
SERVER_GET_FILE_FORMAT_FOR_COOKIE,
|
SERVER_GET_FILE_FORMAT_FOR_COOKIE,
|
||||||
|
SERVER_GET_CODEC_INFO_FOR_COOKIE,
|
||||||
SERVER_GET_ENCODER_FOR_CODEC_INFO,
|
SERVER_GET_ENCODER_FOR_CODEC_INFO,
|
||||||
SERVER_MESSAGE_END,
|
SERVER_MESSAGE_END,
|
||||||
NODE_MESSAGE_START = 0x200,
|
NODE_MESSAGE_START = 0x200,
|
||||||
@@ -844,6 +845,18 @@ struct server_get_file_format_reply : reply_data {
|
|||||||
// the file format matching the cookie
|
// 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 {
|
struct node_request_completed_command : command_data {
|
||||||
media_request_info info;
|
media_request_info info;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -30,6 +30,13 @@ public:
|
|||||||
Encoder();
|
Encoder();
|
||||||
virtual ~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,
|
virtual status_t SetFormat(const media_file_format& fileFormat,
|
||||||
media_format* _inOutEncodedFormat) = 0;
|
media_format* _inOutEncodedFormat) = 0;
|
||||||
|
|
||||||
@@ -75,17 +82,11 @@ public:
|
|||||||
virtual Encoder* NewEncoder(
|
virtual Encoder* NewEncoder(
|
||||||
const media_codec_info& codecInfo) = 0;
|
const media_codec_info& codecInfo) = 0;
|
||||||
|
|
||||||
// TODO: Maybe this also needs to return a media_format with wild cards
|
virtual status_t RegisterNextEncoder(int32* cookie,
|
||||||
// so that we can support the respective get_next_encoder() functions
|
media_codec_info* codecInfo,
|
||||||
// that take media_formats with wild cards and specialize them.
|
media_format_family* formatFamily,
|
||||||
// Then this interface could be turned into an iterator like interface:
|
media_format* inputFormat,
|
||||||
//
|
media_format* outputFormat) = 0;
|
||||||
// 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;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} } // namespace BPrivate::media
|
} } // namespace BPrivate::media
|
||||||
|
|||||||
@@ -7,22 +7,32 @@
|
|||||||
#include "EncoderTable.h"
|
#include "EncoderTable.h"
|
||||||
|
|
||||||
|
|
||||||
const media_codec_info gEncoderTable[] = {
|
const EncoderDescription gEncoderTable[] = {
|
||||||
{
|
{
|
||||||
"MPEG2 Video",
|
{
|
||||||
"mpeg2video",
|
"MPEG2 Video",
|
||||||
0,
|
"mpeg2video",
|
||||||
0,
|
0,
|
||||||
{ 0 }
|
0,
|
||||||
|
{ 0 }
|
||||||
|
},
|
||||||
|
B_ANY_FORMAT_FAMILY,
|
||||||
|
B_MEDIA_RAW_VIDEO,
|
||||||
|
B_MEDIA_ENCODED_VIDEO
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"WAV",
|
{
|
||||||
"wav",
|
"WAV",
|
||||||
0,
|
"wav",
|
||||||
0,
|
0,
|
||||||
{ 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>
|
#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;
|
extern const size_t gEncoderCount;
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -139,11 +139,20 @@ FFmpegPlugin::NewEncoder(const media_codec_info& codecInfo)
|
|||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
FFmpegPlugin::GetSupportedCodecs(const media_codec_info** _codecInfos,
|
FFmpegPlugin::RegisterNextEncoder(int32* cookie, media_codec_info* _codecInfo,
|
||||||
size_t* _count)
|
media_format_family* _formatFamily, media_format* _inputFormat,
|
||||||
|
media_format* _outputFormat)
|
||||||
{
|
{
|
||||||
*_codecInfos = gEncoderTable;
|
if (*cookie < 0 || *cookie >= (int32)gEncoderCount)
|
||||||
*_count = 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;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -34,9 +34,11 @@ public:
|
|||||||
|
|
||||||
virtual Encoder* NewEncoder(
|
virtual Encoder* NewEncoder(
|
||||||
const media_codec_info& codecInfo);
|
const media_codec_info& codecInfo);
|
||||||
virtual status_t GetSupportedCodecs(
|
virtual status_t RegisterNextEncoder(int32* cookie,
|
||||||
const media_codec_info** codecInfos,
|
media_codec_info* codecInfo,
|
||||||
size_t* count);
|
media_format_family* formatFamily,
|
||||||
|
media_format* inputFormat,
|
||||||
|
media_format* outputFormat);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
class GlobalInitilizer {
|
class GlobalInitilizer {
|
||||||
|
|||||||
@@ -28,31 +28,115 @@ static bigtime_t sLastFormatsUpdate;
|
|||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
get_next_encoder(int32* cookie, const media_file_format* _fileFormat,
|
get_next_encoder(int32* cookie, const media_file_format* fileFormat,
|
||||||
const media_format* inFormat, media_format* _outFormat,
|
const media_format* inputFormat, media_format* _outputFormat,
|
||||||
media_codec_info* _codecInfo)
|
media_codec_info* _codecInfo)
|
||||||
{
|
{
|
||||||
UNIMPLEMENTED();
|
// TODO: If fileFormat is provided (existing apps also pass NULL),
|
||||||
return B_ERROR;
|
// 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
|
status_t
|
||||||
get_next_encoder(int32* cookie, const media_file_format* _fileFormat,
|
get_next_encoder(int32* cookie, const media_file_format* fileFormat,
|
||||||
const media_format* inFormat, const media_format* _outFormat,
|
const media_format* inputFormat, const media_format* outputFormat,
|
||||||
media_codec_info* _codecInfo, media_format* _acceptedInputFormat,
|
media_codec_info* _codecInfo, media_format* _acceptedInputFormat,
|
||||||
media_format* _acceptedOutputFormat)
|
media_format* _acceptedOutputFormat)
|
||||||
{
|
{
|
||||||
UNIMPLEMENTED();
|
// TODO: If fileFormat is provided (existing apps also pass NULL),
|
||||||
return B_ERROR;
|
// 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
|
status_t
|
||||||
get_next_encoder(int32* cookie, media_codec_info* _codecInfo)
|
get_next_encoder(int32* cookie, media_codec_info* _codecInfo)
|
||||||
{
|
{
|
||||||
UNIMPLEMENTED();
|
if (cookie == NULL || _codecInfo == NULL)
|
||||||
return B_ERROR;
|
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;
|
encoder_info* info;
|
||||||
for (fEncoderList.Rewind(); fEncoderList.GetNext(&info);) {
|
for (fEncoderList.Rewind(); fEncoderList.GetNext(&info);) {
|
||||||
// check if the encoder matches the supplied format
|
// check if the encoder matches the supplied format
|
||||||
if (info->internalID == id) {
|
if (info->internalID == (uint32)id) {
|
||||||
printf("AddOnManager::GetEncoderForFormat: found encoder %s for "
|
printf("AddOnManager::GetEncoderForFormat: found encoder %s for "
|
||||||
"id %ld\n", info->ref.name, id);
|
"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 -
|
// #pragma mark -
|
||||||
|
|
||||||
|
|
||||||
@@ -439,34 +459,39 @@ AddOnManager::_RegisterEncoder(EncoderPlugin* plugin, const entry_ref& ref)
|
|||||||
encoder_info* pinfo;
|
encoder_info* pinfo;
|
||||||
for (fEncoderList.Rewind(); fEncoderList.GetNext(&pinfo);) {
|
for (fEncoderList.Rewind(); fEncoderList.GetNext(&pinfo);) {
|
||||||
if (!strcmp(pinfo->ref.name, ref.name)) {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("AddOnManager::_RegisterEncoder, name %s\n", ref.name);
|
printf("AddOnManager::_RegisterEncoder, name %s\n", ref.name);
|
||||||
|
|
||||||
|
// Get list of supported encoders...
|
||||||
|
|
||||||
encoder_info info;
|
encoder_info info;
|
||||||
info.ref = ref;
|
info.ref = ref;
|
||||||
info.internalID = fNextEncoderCodecInfoID++;
|
info.internalID = fNextEncoderCodecInfoID++;
|
||||||
|
|
||||||
// Get list of supported codecs...
|
int32 cookie = 0;
|
||||||
const media_codec_info* codecInfos = NULL;
|
int32 subID = 0;
|
||||||
size_t count = 0;
|
|
||||||
if (plugin->GetSupportedCodecs(&codecInfos, &count) != B_OK) {
|
|
||||||
printf("AddOnManager::_RegisterEncoder(): plugin->GetSupportedCodecs"
|
|
||||||
"(...) failed!\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (uint32 i = 0 ; i < count ; i++) {
|
while (true) {
|
||||||
media_codec_info codecInfo = codecInfos[i];
|
memset(&info.codecInfo, 0, sizeof(media_codec_info));
|
||||||
codecInfo.id = info.internalID;
|
memset(&info.intputFormat, 0, sizeof(media_format));
|
||||||
codecInfo.sub_id = i;
|
memset(&info.outputFormat, 0, sizeof(media_format));
|
||||||
info.codecInfos.Insert(codecInfo);
|
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,
|
status_t GetFileFormat(media_file_format* _fileFormat,
|
||||||
int32 cookie);
|
int32 cookie);
|
||||||
|
status_t GetCodecInfo(media_codec_info* _codecInfo,
|
||||||
|
media_format_family* _formatFamily,
|
||||||
|
media_format* _inputFormat,
|
||||||
|
media_format* _outputFormat, int32 cookie);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
status_t _RegisterAddOn(BEntry& entry);
|
status_t _RegisterAddOn(BEntry& entry);
|
||||||
@@ -78,7 +82,10 @@ private:
|
|||||||
struct encoder_info {
|
struct encoder_info {
|
||||||
entry_ref ref;
|
entry_ref ref;
|
||||||
uint32 internalID;
|
uint32 internalID;
|
||||||
List<media_codec_info> codecInfos;
|
media_codec_info codecInfo;
|
||||||
|
media_format_family formatFamily;
|
||||||
|
media_format intputFormat;
|
||||||
|
media_format outputFormat;
|
||||||
};
|
};
|
||||||
|
|
||||||
BLocker fLock;
|
BLocker fLock;
|
||||||
|
|||||||
@@ -908,6 +908,19 @@ ServerApp::HandleMessage(int32 code, void *data, size_t size)
|
|||||||
break;
|
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:
|
case SERVER_GET_ENCODER_FOR_CODEC_INFO:
|
||||||
{
|
{
|
||||||
const server_get_encoder_for_codec_info_request *request
|
const server_get_encoder_for_codec_info_request *request
|
||||||
|
|||||||
Reference in New Issue
Block a user