* Coding style cleanup, some removal of dead code.
* Refactored NegotiateOutputFormat() and Decode() into two separate private methods each, one for video and one for audio. * Keep reading chunks when video decoding, until we have got a picture. This gets us scrambled video instead of a black picture for h264 in mpegts. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@31457 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -12,12 +12,13 @@
|
||||
|
||||
#include "AVCodecDecoder.h"
|
||||
|
||||
#include <Debug.h>
|
||||
#include <OS.h>
|
||||
#include <Bitmap.h>
|
||||
#include <new>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#define DO_PROFILING 0
|
||||
#include <Bitmap.h>
|
||||
#include <Debug.h>
|
||||
|
||||
|
||||
#undef TRACE
|
||||
//#define TRACE_AV_CODEC
|
||||
@@ -27,6 +28,7 @@
|
||||
# define TRACE(x...)
|
||||
#endif
|
||||
|
||||
|
||||
struct wave_format_ex {
|
||||
uint16 format_tag;
|
||||
uint16 channels;
|
||||
@@ -38,56 +40,68 @@ struct wave_format_ex {
|
||||
// extra_data[extra_size]
|
||||
} _PACKED;
|
||||
|
||||
static bigtime_t diff1 = 0, diff2 = 0;
|
||||
static long prof_cnt = 0;
|
||||
|
||||
// uncommenting will make Decode() set the current thread priority to time
|
||||
// sharing, so it won't totally freeze if you busy-loop in there (to help debug
|
||||
// with CD Manager)
|
||||
//#define UNREAL
|
||||
// profiling related globals
|
||||
#define DO_PROFILING 0
|
||||
|
||||
static bigtime_t decodingTime = 0;
|
||||
static bigtime_t conversionTime = 0;
|
||||
static long profileCounter = 0;
|
||||
|
||||
|
||||
AVCodecDecoder::AVCodecDecoder()
|
||||
: fHeader(),
|
||||
:
|
||||
fHeader(),
|
||||
fInfo(),
|
||||
fInputFormat(),
|
||||
fOutputVideoFormat(),
|
||||
fFrame(0),
|
||||
isAudio(false),
|
||||
fIsAudio(false),
|
||||
fCodecIndexInTable(-1),
|
||||
fCodec(NULL),
|
||||
ffc(NULL),
|
||||
fContext(avcodec_alloc_context()),
|
||||
fInputPicture(avcodec_alloc_frame()),
|
||||
fOutputPicture(avcodec_alloc_frame()),
|
||||
|
||||
fCodecInitDone(false),
|
||||
conv_func(NULL),
|
||||
|
||||
fFormatConversionFunc(NULL),
|
||||
|
||||
fExtraData(NULL),
|
||||
fExtraDataSize(0),
|
||||
fBlockAlign(0),
|
||||
fOutputBuffer(0)
|
||||
|
||||
fStartTime(0),
|
||||
fOutputFrameCount(0),
|
||||
fOutputFrameRate(1.0),
|
||||
fOutputFrameSize(0),
|
||||
|
||||
fOutputBuffer(NULL),
|
||||
fOutputBufferOffset(0),
|
||||
fOutputBufferSize(0)
|
||||
{
|
||||
TRACE("AVCodecDecoder::AVCodecDecoder()\n");
|
||||
|
||||
ffc = avcodec_alloc_context();
|
||||
ffpicture = avcodec_alloc_frame();
|
||||
opicture = avcodec_alloc_frame();
|
||||
}
|
||||
|
||||
|
||||
AVCodecDecoder::~AVCodecDecoder()
|
||||
{
|
||||
TRACE("[%c] AVCodecDecoder::~AVCodecDecoder()\n", isAudio?('a'):('v'));
|
||||
TRACE("[%c] AVCodecDecoder::~AVCodecDecoder()\n", fIsAudio?('a'):('v'));
|
||||
|
||||
#ifdef DO_PROFILING
|
||||
if (prof_cnt > 0) {
|
||||
if (profileCounter > 0) {
|
||||
printf("[%c] profile: d1 = %lld, d2 = %lld (%Ld)\n",
|
||||
isAudio?('a'):('v'), diff1/prof_cnt, diff2/prof_cnt,
|
||||
fIsAudio?('a'):('v'), decodingTime / profileCounter, conversionTime / profileCounter,
|
||||
fFrame);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (fCodecInitDone)
|
||||
avcodec_close(ffc);
|
||||
avcodec_close(fContext);
|
||||
|
||||
free(opicture);
|
||||
free(ffpicture);
|
||||
free(ffc);
|
||||
free(fOutputPicture);
|
||||
free(fInputPicture);
|
||||
free(fContext);
|
||||
|
||||
delete [] fExtraData;
|
||||
delete [] fOutputBuffer;
|
||||
@@ -95,45 +109,47 @@ AVCodecDecoder::~AVCodecDecoder()
|
||||
|
||||
|
||||
void
|
||||
AVCodecDecoder::GetCodecInfo(media_codec_info *mci)
|
||||
AVCodecDecoder::GetCodecInfo(media_codec_info* mci)
|
||||
{
|
||||
sprintf(mci->short_name, "ff:%s", fCodec->name);
|
||||
sprintf(mci->pretty_name, "%s (libavcodec %s)",
|
||||
gCodecTable[ffcodec_index_in_table].prettyname, fCodec->name);
|
||||
gCodecTable[fCodecIndexInTable].prettyname, fCodec->name);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
AVCodecDecoder::Setup(media_format *ioEncodedFormat, const void *infoBuffer,
|
||||
AVCodecDecoder::Setup(media_format* ioEncodedFormat, const void* infoBuffer,
|
||||
size_t infoSize)
|
||||
{
|
||||
if (ioEncodedFormat->type != B_MEDIA_ENCODED_AUDIO
|
||||
&& ioEncodedFormat->type != B_MEDIA_ENCODED_VIDEO)
|
||||
return B_ERROR;
|
||||
|
||||
isAudio = (ioEncodedFormat->type == B_MEDIA_ENCODED_AUDIO);
|
||||
TRACE("[%c] AVCodecDecoder::Setup()\n", isAudio?('a'):('v'));
|
||||
fIsAudio = (ioEncodedFormat->type == B_MEDIA_ENCODED_AUDIO);
|
||||
TRACE("[%c] AVCodecDecoder::Setup()\n", fIsAudio?('a'):('v'));
|
||||
|
||||
if (isAudio && !fOutputBuffer)
|
||||
if (fIsAudio && !fOutputBuffer)
|
||||
fOutputBuffer = new char[AVCODEC_MAX_AUDIO_FRAME_SIZE];
|
||||
|
||||
//#if DEBUG
|
||||
#ifdef TRACE_AV_CODEC
|
||||
char buffer[1024];
|
||||
string_for_format(*ioEncodedFormat, buffer, sizeof(buffer));
|
||||
TRACE("[%c] input_format=%s\n", isAudio?('a'):('v'), buffer);
|
||||
TRACE("[%c] infoSize=%ld\n", isAudio?('a'):('v'), infoSize);
|
||||
TRACE("[%c] user_data_type=%08lx\n", isAudio?('a'):('v'), ioEncodedFormat->user_data_type);
|
||||
TRACE("[%c] meta_data_size=%ld\n", isAudio?('a'):('v'), ioEncodedFormat->MetaDataSize());
|
||||
TRACE("[%c] info_size=%ld\n", isAudio?('a'):('v'), infoSize);
|
||||
//#endif
|
||||
TRACE("[%c] input_format = %s\n", fIsAudio?('a'):('v'), buffer);
|
||||
TRACE("[%c] infoSize = %ld\n", fIsAudio?('a'):('v'), infoSize);
|
||||
TRACE("[%c] user_data_type = %08lx\n", fIsAudio?('a'):('v'),
|
||||
ioEncodedFormat->user_data_type);
|
||||
TRACE("[%c] meta_data_size = %ld\n", fIsAudio?('a'):('v'),
|
||||
ioEncodedFormat->MetaDataSize());
|
||||
TRACE("[%c] info_size = %ld\n", fIsAudio?('a'):('v'), infoSize);
|
||||
#endif
|
||||
|
||||
media_format_description descr;
|
||||
for (int32 i = 0; gCodecTable[i].id; i++) {
|
||||
ffcodec_index_in_table = i;
|
||||
fCodecIndexInTable = i;
|
||||
uint64 cid;
|
||||
|
||||
if (BMediaFormats().GetCodeFor(*ioEncodedFormat, gCodecTable[i].family,
|
||||
&descr) == B_OK
|
||||
if (BMediaFormats().GetCodeFor(*ioEncodedFormat,
|
||||
gCodecTable[i].family, &descr) == B_OK
|
||||
&& gCodecTable[i].type == ioEncodedFormat->type) {
|
||||
switch(gCodecTable[i].family) {
|
||||
case B_WAV_FORMAT_FAMILY:
|
||||
@@ -159,21 +175,22 @@ AVCodecDecoder::Setup(media_format *ioEncodedFormat, const void *infoBuffer,
|
||||
puts("ERR family");
|
||||
return B_ERROR;
|
||||
}
|
||||
TRACE(" 0x%04lx codec id = \"%c%c%c%c\"\n", uint32(cid), (char)((cid >> 24) & 0xff),
|
||||
(char)((cid >> 16) & 0xff), (char)((cid >> 8) & 0xff),
|
||||
(char)(cid & 0xff));
|
||||
TRACE(" 0x%04lx codec id = \"%c%c%c%c\"\n", uint32(cid),
|
||||
(char)((cid >> 24) & 0xff), (char)((cid >> 16) & 0xff),
|
||||
(char)((cid >> 8) & 0xff), (char)(cid & 0xff));
|
||||
|
||||
if (gCodecTable[i].family == descr.family
|
||||
&& gCodecTable[i].fourcc == cid) {
|
||||
fCodec = avcodec_find_decoder(gCodecTable[i].id);
|
||||
if (!fCodec) {
|
||||
TRACE("AVCodecDecoder: unable to find the correct ffmpeg decoder "
|
||||
"(id = %d)!!!\n",gCodecTable[i].id);
|
||||
TRACE("AVCodecDecoder: unable to find the correct ffmpeg "
|
||||
"decoder (id = %d)!!!\n",gCodecTable[i].id);
|
||||
return B_ERROR;
|
||||
}
|
||||
TRACE("AVCodecDecoder: found decoder %s\n",fCodec->name);
|
||||
|
||||
if (gCodecTable[i].family == B_WAV_FORMAT_FAMILY && infoSize >= sizeof(wave_format_ex)) {
|
||||
if (gCodecTable[i].family == B_WAV_FORMAT_FAMILY
|
||||
&& infoSize >= sizeof(wave_format_ex)) {
|
||||
const wave_format_ex *wfmt_data
|
||||
= (const wave_format_ex *)infoBuffer;
|
||||
size_t wfmt_size = infoSize;
|
||||
@@ -186,12 +203,16 @@ AVCodecDecoder::Setup(media_format *ioEncodedFormat, const void *infoBuffer,
|
||||
}
|
||||
}
|
||||
} else {
|
||||
fBlockAlign = ioEncodedFormat->u.encoded_audio.output.buffer_size;
|
||||
TRACE("AVCodecDecoder: extra data size %ld\n",infoSize);
|
||||
fBlockAlign
|
||||
= ioEncodedFormat->u.encoded_audio.output.buffer_size;
|
||||
TRACE("AVCodecDecoder: extra data size %ld\n", infoSize);
|
||||
fExtraDataSize = infoSize;
|
||||
if (fExtraDataSize) {
|
||||
fExtraData = new char [fExtraDataSize];
|
||||
fExtraData = new(std::nothrow) char[fExtraDataSize];
|
||||
if (fExtraData != NULL)
|
||||
memcpy(fExtraData, infoBuffer, fExtraDataSize);
|
||||
else
|
||||
fExtraDataSize = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -206,27 +227,28 @@ AVCodecDecoder::Setup(media_format *ioEncodedFormat, const void *infoBuffer,
|
||||
|
||||
|
||||
status_t
|
||||
AVCodecDecoder::Seek(uint32 seekTo,
|
||||
int64 seekFrame, int64 *frame,
|
||||
bigtime_t seekTime, bigtime_t *time)
|
||||
AVCodecDecoder::Seek(uint32 seekTo, int64 seekFrame, int64* frame,
|
||||
bigtime_t seekTime, bigtime_t* time)
|
||||
{
|
||||
// reset the ffmpeg codec
|
||||
// to flush buffers, so we keep the sync
|
||||
if (isAudio && fCodecInitDone) {
|
||||
// Reset the FFmpeg codec to flush buffers, so we keep the sync
|
||||
// TODO: Maybe that should be done for video codecs, too?
|
||||
if (fIsAudio && fCodecInitDone) {
|
||||
fCodecInitDone = false;
|
||||
avcodec_close(ffc);
|
||||
fCodecInitDone = (avcodec_open(ffc, fCodec) >= 0);
|
||||
avcodec_close(fContext);
|
||||
fCodecInitDone = (avcodec_open(fContext, fCodec) >= 0);
|
||||
}
|
||||
|
||||
if (seekTo == B_MEDIA_SEEK_TO_TIME) {
|
||||
TRACE("AVCodecDecoder::Seek by time ");
|
||||
TRACE("from frame %Ld and time %.6f TO Required Time %.6f. ", fFrame, fStartTime / 1000000.0, seekTime / 1000000.0);
|
||||
TRACE("from frame %Ld and time %.6f TO Required Time %.6f. ",
|
||||
fFrame, fStartTime / 1000000.0, seekTime / 1000000.0);
|
||||
|
||||
*frame = (int64)(seekTime * fOutputFrameRate / 1000000LL);
|
||||
*time = seekTime;
|
||||
} else if (seekTo == B_MEDIA_SEEK_TO_FRAME) {
|
||||
TRACE("AVCodecDecoder::Seek by Frame ");
|
||||
TRACE("from time %.6f and frame %Ld TO Required Frame %Ld. ", fStartTime / 1000000.0, fFrame, seekFrame);
|
||||
TRACE("from time %.6f and frame %Ld TO Required Frame %Ld. ",
|
||||
fStartTime / 1000000.0, fFrame, seekFrame);
|
||||
|
||||
*time = (bigtime_t)(seekFrame * 1000000LL / fOutputFrameRate);
|
||||
*frame = seekFrame;
|
||||
@@ -241,19 +263,56 @@ AVCodecDecoder::Seek(uint32 seekTo,
|
||||
|
||||
|
||||
status_t
|
||||
AVCodecDecoder::NegotiateOutputFormat(media_format *inout_format)
|
||||
AVCodecDecoder::NegotiateOutputFormat(media_format* inOutFormat)
|
||||
{
|
||||
TRACE("[%c] AVCodecDecoder::NegotiateOutputFormat()\n", isAudio?('a'):('v'));
|
||||
TRACE("AVCodecDecoder::NegotiateOutputFormat()\n",
|
||||
fIsAudio?('a'):('v'));
|
||||
|
||||
int result;
|
||||
|
||||
#if DEBUG
|
||||
#if TRACE_AV_CODEC
|
||||
char buffer[1024];
|
||||
string_for_format(*inout_format, buffer, sizeof(buffer));
|
||||
TRACE("[%c] in_format=%s\n", isAudio?('a'):('v'), buffer);
|
||||
string_for_format(*inOutFormat, buffer, sizeof(buffer));
|
||||
TRACE(" [%c] requested format = %s\n", fIsAudio?('a'):('v'), buffer);
|
||||
#endif
|
||||
|
||||
if (isAudio) {
|
||||
if (fIsAudio)
|
||||
return _NegotiateAudioOutputFormat(inOutFormat);
|
||||
else
|
||||
return _NegotiateVideoOutputFormat(inOutFormat);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
AVCodecDecoder::Decode(void* outBuffer, int64* outFrameCount,
|
||||
media_header* mediaHeader, media_decode_info* info)
|
||||
{
|
||||
if (!fCodecInitDone)
|
||||
return B_NO_INIT;
|
||||
|
||||
// TRACE("[%c] AVCodecDecoder::Decode() for time %Ld\n", fIsAudio?('a'):('v'),
|
||||
// fStartTime);
|
||||
|
||||
mediaHeader->start_time = fStartTime;
|
||||
|
||||
status_t ret;
|
||||
if (fIsAudio)
|
||||
ret = _DecodeAudio(outBuffer, outFrameCount, mediaHeader, info);
|
||||
else
|
||||
ret = _DecodeVideo(outBuffer, outFrameCount, mediaHeader, info);
|
||||
|
||||
fStartTime = (bigtime_t)(1000000LL * fFrame / fOutputFrameRate);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
status_t
|
||||
AVCodecDecoder::_NegotiateAudioOutputFormat(media_format* inOutFormat)
|
||||
{
|
||||
TRACE("AVCodecDecoder::_NegotiateAudioOutputFormat()\n");
|
||||
|
||||
media_multi_audio_format outputAudioFormat;
|
||||
outputAudioFormat = media_raw_audio_format::wildcard;
|
||||
outputAudioFormat.format = media_raw_audio_format::B_AUDIO_SHORT;
|
||||
@@ -264,32 +323,34 @@ AVCodecDecoder::NegotiateOutputFormat(media_format *inout_format)
|
||||
= fInputFormat.u.encoded_audio.output.channel_count;
|
||||
outputAudioFormat.buffer_size
|
||||
= 1024 * fInputFormat.u.encoded_audio.output.channel_count;
|
||||
inout_format->type = B_MEDIA_RAW_AUDIO;
|
||||
inout_format->u.raw_audio = outputAudioFormat;
|
||||
inOutFormat->type = B_MEDIA_RAW_AUDIO;
|
||||
inOutFormat->u.raw_audio = outputAudioFormat;
|
||||
|
||||
ffc->bit_rate = (int) fInputFormat.u.encoded_audio.bit_rate;
|
||||
ffc->sample_rate = (int) fInputFormat.u.encoded_audio.output.frame_rate;
|
||||
ffc->channels = fInputFormat.u.encoded_audio.output.channel_count;
|
||||
ffc->block_align = fBlockAlign;
|
||||
ffc->extradata = (uint8_t *)fExtraData;
|
||||
ffc->extradata_size = fExtraDataSize;
|
||||
fContext->bit_rate = (int)fInputFormat.u.encoded_audio.bit_rate;
|
||||
fContext->sample_rate
|
||||
= (int)fInputFormat.u.encoded_audio.output.frame_rate;
|
||||
fContext->channels = fInputFormat.u.encoded_audio.output.channel_count;
|
||||
fContext->block_align = fBlockAlign;
|
||||
fContext->extradata = (uint8_t*)fExtraData;
|
||||
fContext->extradata_size = fExtraDataSize;
|
||||
|
||||
TRACE("bit_rate %d, sample_rate %d, channels %d, block_align %d, "
|
||||
"extradata_size %d\n", ffc->bit_rate, ffc->sample_rate,
|
||||
ffc->channels, ffc->block_align, ffc->extradata_size);
|
||||
"extradata_size %d\n", fContext->bit_rate, fContext->sample_rate,
|
||||
fContext->channels, fContext->block_align, fContext->extradata_size);
|
||||
|
||||
// close any previous instance
|
||||
if (fCodecInitDone) {
|
||||
fCodecInitDone = false;
|
||||
avcodec_close(ffc);
|
||||
avcodec_close(fContext);
|
||||
}
|
||||
|
||||
// open new
|
||||
result = avcodec_open(ffc, fCodec);
|
||||
int result = avcodec_open(fContext, fCodec);
|
||||
fCodecInitDone = (result >= 0);
|
||||
|
||||
TRACE("audio: bit_rate = %d, sample_rate = %d, chans = %d Init = %d\n",
|
||||
ffc->bit_rate, ffc->sample_rate, ffc->channels, result);
|
||||
fContext->bit_rate, fContext->sample_rate, fContext->channels,
|
||||
result);
|
||||
|
||||
fStartTime = 0;
|
||||
fOutputFrameSize = 2 * outputAudioFormat.channel_count;
|
||||
@@ -301,8 +362,8 @@ AVCodecDecoder::NegotiateOutputFormat(media_format *inout_format)
|
||||
fOutputBufferOffset = 0;
|
||||
fOutputBufferSize = 0;
|
||||
|
||||
inout_format->require_flags = 0;
|
||||
inout_format->deny_flags = B_MEDIA_MAUI_UNDEFINED_FLAGS;
|
||||
inOutFormat->require_flags = 0;
|
||||
inOutFormat->deny_flags = B_MEDIA_MAUI_UNDEFINED_FLAGS;
|
||||
|
||||
if (!fCodecInitDone) {
|
||||
TRACE("avcodec_open() failed!\n");
|
||||
@@ -310,56 +371,63 @@ AVCodecDecoder::NegotiateOutputFormat(media_format *inout_format)
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
} else { // VIDEO
|
||||
|
||||
status_t
|
||||
AVCodecDecoder::_NegotiateVideoOutputFormat(media_format* inOutFormat)
|
||||
{
|
||||
TRACE("AVCodecDecoder::_NegotiateVideoOutputFormat()\n");
|
||||
|
||||
fOutputVideoFormat = fInputFormat.u.encoded_video.output;
|
||||
|
||||
ffc->width = fOutputVideoFormat.display.line_width;
|
||||
ffc->height = fOutputVideoFormat.display.line_count;
|
||||
// ffc->frame_rate = (int)(fOutputVideoFormat.field_rate
|
||||
// * ffc->frame_rate_base);
|
||||
fContext->width = fOutputVideoFormat.display.line_width;
|
||||
fContext->height = fOutputVideoFormat.display.line_count;
|
||||
// fContext->frame_rate = (int)(fOutputVideoFormat.field_rate
|
||||
// * fContext->frame_rate_base);
|
||||
|
||||
fOutputFrameRate = fOutputVideoFormat.field_rate;
|
||||
|
||||
ffc->extradata = (uint8_t *)fExtraData;
|
||||
ffc->extradata_size = fExtraDataSize;
|
||||
fContext->extradata = (uint8_t *)fExtraData;
|
||||
fContext->extradata_size = fExtraDataSize;
|
||||
|
||||
// if (fInputFormat.MetaDataSize() > 0) {
|
||||
// ffc->extradata = (uint8_t *)fInputFormat.MetaData();
|
||||
// ffc->extradata_size = fInputFormat.MetaDataSize();
|
||||
// fContext->extradata = (uint8_t *)fInputFormat.MetaData();
|
||||
// fContext->extradata_size = fInputFormat.MetaDataSize();
|
||||
// }
|
||||
|
||||
TRACE("#### requested video format 0x%x\n",
|
||||
inout_format->u.raw_video.display.format);
|
||||
TRACE(" requested video format 0x%x\n",
|
||||
inOutFormat->u.raw_video.display.format);
|
||||
|
||||
// make MediaPlayer happy (if not in rgb32 screen depth and no overlay,
|
||||
// Make MediaPlayer happy (if not in rgb32 screen depth and no overlay,
|
||||
// it will only ask for YCbCr, which DrawBitmap doesn't handle, so the
|
||||
// default colordepth is RGB32)
|
||||
if (inout_format->u.raw_video.display.format == B_YCbCr422)
|
||||
// default colordepth is RGB32).
|
||||
if (inOutFormat->u.raw_video.display.format == B_YCbCr422)
|
||||
fOutputVideoFormat.display.format = B_YCbCr422;
|
||||
else
|
||||
fOutputVideoFormat.display.format = B_RGB32;
|
||||
|
||||
// search for a pixel-format the codec handles
|
||||
// XXX We should try this a couple of times until it succeeds, each time
|
||||
// XXX using another format pixel-format that is supported by the
|
||||
// XXX decoder. But libavcodec doesn't seem to offer any way to tell the
|
||||
// XXX decoder which format it should use.
|
||||
conv_func = 0;
|
||||
for (int i = 0; i < 1; i++) { // iterate over supported codec formats
|
||||
// Search for a pixel-format the codec handles
|
||||
// TODO: We should try this a couple of times until it succeeds, each
|
||||
// time using another pixel-format that is supported by the decoder.
|
||||
// But libavcodec doesn't seem to offer any way to tell the decoder
|
||||
// which format it should use.
|
||||
fFormatConversionFunc = 0;
|
||||
// Iterate over supported codec formats
|
||||
for (int i = 0; i < 1; i++) {
|
||||
// close any previous instance
|
||||
if (fCodecInitDone) {
|
||||
fCodecInitDone = false;
|
||||
avcodec_close(ffc);
|
||||
avcodec_close(fContext);
|
||||
}
|
||||
// XXX set n-th ffc->pix_fmt here
|
||||
if (avcodec_open(ffc, fCodec) >= 0) {
|
||||
// TODO: Set n-th fContext->pix_fmt here
|
||||
if (avcodec_open(fContext, fCodec) >= 0) {
|
||||
fCodecInitDone = true;
|
||||
|
||||
conv_func = resolve_colorspace(fOutputVideoFormat.display.format, ffc->pix_fmt);
|
||||
fFormatConversionFunc = resolve_colorspace(
|
||||
fOutputVideoFormat.display.format, fContext->pix_fmt);
|
||||
}
|
||||
if (conv_func != 0)
|
||||
if (fFormatConversionFunc != NULL)
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -368,8 +436,9 @@ AVCodecDecoder::NegotiateOutputFormat(media_format *inout_format)
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
if (!conv_func) {
|
||||
TRACE("no conv_func found or decoder has not set the pixel format yet!\n");
|
||||
if (fFormatConversionFunc == NULL) {
|
||||
TRACE("no pixel format conversion function found or decoder has "
|
||||
"not set the pixel format yet!\n");
|
||||
}
|
||||
|
||||
if (fOutputVideoFormat.display.format == B_YCbCr422) {
|
||||
@@ -380,53 +449,33 @@ AVCodecDecoder::NegotiateOutputFormat(media_format *inout_format)
|
||||
= 4 * fOutputVideoFormat.display.line_width;
|
||||
}
|
||||
|
||||
inout_format->type = B_MEDIA_RAW_VIDEO;
|
||||
inout_format->u.raw_video = fOutputVideoFormat;
|
||||
inOutFormat->type = B_MEDIA_RAW_VIDEO;
|
||||
inOutFormat->u.raw_video = fOutputVideoFormat;
|
||||
|
||||
inout_format->require_flags = 0;
|
||||
inout_format->deny_flags = B_MEDIA_MAUI_UNDEFINED_FLAGS;
|
||||
inOutFormat->require_flags = 0;
|
||||
inOutFormat->deny_flags = B_MEDIA_MAUI_UNDEFINED_FLAGS;
|
||||
|
||||
#if DEBUG
|
||||
string_for_format(*inout_format, buffer, sizeof(buffer));
|
||||
TRACE("[%c] out_format=%s\n", isAudio?('a'):('v'), buffer);
|
||||
#endif
|
||||
|
||||
TRACE("#### returned video format 0x%x\n",
|
||||
inout_format->u.raw_video.display.format);
|
||||
#if TRACE_AV_CODEC
|
||||
char buffer[1024];
|
||||
string_for_format(*inOutFormat, buffer, sizeof(buffer));
|
||||
TRACE("[v] outFormat = %s\n", buffer);
|
||||
TRACE(" returned video format 0x%x\n",
|
||||
inOutFormat->u.raw_video.display.format);
|
||||
#endif
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
AVCodecDecoder::Decode(void *out_buffer, int64 *out_frameCount,
|
||||
media_header *mh, media_decode_info *info)
|
||||
AVCodecDecoder::_DecodeAudio(void* outBuffer, int64* outFrameCount,
|
||||
media_header* mediaHeader, media_decode_info* info)
|
||||
{
|
||||
const void *data;
|
||||
// TRACE("audio start_time %.6f\n", mediaHeader->start_time / 1000000.0);
|
||||
|
||||
if (!fCodecInitDone)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
#ifdef DO_PROFILING
|
||||
bigtime_t prof_t1, prof_t2, prof_t3;
|
||||
#endif
|
||||
|
||||
#ifdef UNREAL
|
||||
set_thread_priority(find_thread(NULL), B_NORMAL_PRIORITY);
|
||||
#endif
|
||||
|
||||
// TRACE("[%c] AVCodecDecoder::Decode() for time %Ld\n", isAudio?('a'):('v'), fStartTime);
|
||||
|
||||
mh->start_time = fStartTime;
|
||||
|
||||
if (isAudio) {
|
||||
|
||||
// TRACE("audio start_time %.6f\n", mh->start_time / 1000000.0);
|
||||
|
||||
char *output_buffer = (char *)out_buffer;
|
||||
*out_frameCount = 0;
|
||||
while (*out_frameCount < fOutputFrameCount) {
|
||||
char* output_buffer = (char*)outBuffer;
|
||||
*outFrameCount = 0;
|
||||
while (*outFrameCount < fOutputFrameCount) {
|
||||
if (fOutputBufferSize < 0) {
|
||||
TRACE("############ fOutputBufferSize %ld\n",
|
||||
fOutputBufferSize);
|
||||
@@ -439,21 +488,21 @@ AVCodecDecoder::Decode(void *out_buffer, int64 *out_frameCount,
|
||||
}
|
||||
|
||||
if (fOutputBufferSize > 0) {
|
||||
int32 frames = min_c(fOutputFrameCount - *out_frameCount,
|
||||
int32 frames = min_c(fOutputFrameCount - *outFrameCount,
|
||||
fOutputBufferSize / fOutputFrameSize);
|
||||
memcpy(output_buffer, fOutputBuffer + fOutputBufferOffset,
|
||||
frames * fOutputFrameSize);
|
||||
fOutputBufferOffset += frames * fOutputFrameSize;
|
||||
fOutputBufferSize -= frames * fOutputFrameSize;
|
||||
output_buffer += frames * fOutputFrameSize;
|
||||
*out_frameCount += frames;
|
||||
*outFrameCount += frames;
|
||||
fStartTime += (bigtime_t)((1000000LL * frames) / fOutputFrameRate);
|
||||
continue;
|
||||
}
|
||||
if (fChunkBufferSize == 0) {
|
||||
media_header chunk_mh;
|
||||
media_header chunkMediaHeader;
|
||||
status_t err;
|
||||
err = GetNextChunk(&fChunkBuffer, &fChunkBufferSize, &chunk_mh);
|
||||
err = GetNextChunk(&fChunkBuffer, &fChunkBufferSize, &chunkMediaHeader);
|
||||
if (err == B_LAST_BUFFER_ERROR) {
|
||||
TRACE("Last Chunk with chunk size %ld\n",fChunkBufferSize);
|
||||
fChunkBufferSize = 0;
|
||||
@@ -465,15 +514,15 @@ AVCodecDecoder::Decode(void *out_buffer, int64 *out_frameCount,
|
||||
break;
|
||||
}
|
||||
fChunkBufferOffset = 0;
|
||||
fStartTime = chunk_mh.start_time;
|
||||
if (*out_frameCount == 0)
|
||||
mh->start_time = chunk_mh.start_time;
|
||||
fStartTime = chunkMediaHeader.start_time;
|
||||
if (*outFrameCount == 0)
|
||||
mediaHeader->start_time = chunkMediaHeader.start_time;
|
||||
continue;
|
||||
}
|
||||
if (fOutputBufferSize == 0) {
|
||||
int len;
|
||||
int out_size = AVCODEC_MAX_AUDIO_FRAME_SIZE;
|
||||
len = avcodec_decode_audio2(ffc, (short *)fOutputBuffer,
|
||||
len = avcodec_decode_audio2(fContext, (short *)fOutputBuffer,
|
||||
&out_size, (uint8_t*)fChunkBuffer + fChunkBufferOffset,
|
||||
fChunkBufferSize);
|
||||
if (len < 0) {
|
||||
@@ -493,111 +542,137 @@ AVCodecDecoder::Decode(void *out_buffer, int64 *out_frameCount,
|
||||
fOutputBufferSize = out_size;
|
||||
}
|
||||
}
|
||||
fFrame += *out_frameCount;
|
||||
fFrame += *outFrameCount;
|
||||
|
||||
// TRACE("Played %Ld frames at time %Ld\n",*out_frameCount, mh->start_time);
|
||||
// TRACE("Played %Ld frames at time %Ld\n",*outFrameCount, mediaHeader->start_time);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
} else { // Video
|
||||
|
||||
media_header chunk_mh;
|
||||
status_t err;
|
||||
status_t
|
||||
AVCodecDecoder::_DecodeVideo(void* outBuffer, int64* outFrameCount,
|
||||
media_header* mediaHeader, media_decode_info* info)
|
||||
{
|
||||
bool firstRun = true;
|
||||
while (true) {
|
||||
const void* data;
|
||||
size_t size;
|
||||
|
||||
err = GetNextChunk(&data, &size, &chunk_mh);
|
||||
media_header chunkMediaHeader;
|
||||
status_t err = GetNextChunk(&data, &size, &chunkMediaHeader);
|
||||
if (err != B_OK) {
|
||||
TRACE("AVCodecDecoder::Decode(): error 0x%08lx from GetNextChunk()\n", err);
|
||||
TRACE("AVCodecDecoder::_DecodeVideo(): error from "
|
||||
"GetNextChunk(): %s\n", strerror(err));
|
||||
return err;
|
||||
}
|
||||
if (firstRun) {
|
||||
firstRun = false;
|
||||
|
||||
mh->type = B_MEDIA_RAW_VIDEO;
|
||||
// mh->start_time = chunk_mh.start_time;
|
||||
mh->file_pos = 0;
|
||||
mh->orig_size = 0;
|
||||
mh->u.raw_video.field_gamma = 1.0;
|
||||
mh->u.raw_video.field_sequence = fFrame;
|
||||
mh->u.raw_video.field_number = 0;
|
||||
mh->u.raw_video.pulldown_number = 0;
|
||||
mh->u.raw_video.first_active_line = 1;
|
||||
mh->u.raw_video.line_count = fOutputVideoFormat.display.line_count;
|
||||
mediaHeader->type = B_MEDIA_RAW_VIDEO;
|
||||
// mediaHeader->start_time = chunkMediaHeader.start_time;
|
||||
mediaHeader->file_pos = 0;
|
||||
mediaHeader->orig_size = 0;
|
||||
mediaHeader->u.raw_video.field_gamma = 1.0;
|
||||
mediaHeader->u.raw_video.field_sequence = fFrame;
|
||||
mediaHeader->u.raw_video.field_number = 0;
|
||||
mediaHeader->u.raw_video.pulldown_number = 0;
|
||||
mediaHeader->u.raw_video.first_active_line = 1;
|
||||
mediaHeader->u.raw_video.line_count
|
||||
= fOutputVideoFormat.display.line_count;
|
||||
|
||||
TRACE("[%c] start_time=%02d:%02d.%02d field_sequence=%lu\n",
|
||||
isAudio ? ('a') : ('v'),
|
||||
int((mh->start_time / 60000000) % 60),
|
||||
int((mh->start_time / 1000000) % 60),
|
||||
int((mh->start_time / 10000) % 100),
|
||||
mh->u.raw_video.field_sequence);
|
||||
|
||||
#ifdef DO_PROFILING
|
||||
prof_t1 = system_time();
|
||||
#endif
|
||||
|
||||
int got_picture = 0;
|
||||
int len;
|
||||
len = avcodec_decode_video(ffc, ffpicture, &got_picture,
|
||||
(uint8_t *)data, size);
|
||||
|
||||
//TRACE("FFDEC: PTS = %d:%d:%d.%d - ffc->frame_number = %ld "
|
||||
// "ffc->frame_rate = %ld\n", (int)(ffc->pts / (60*60*1000000)),
|
||||
// (int)(ffc->pts / (60*1000000)), (int)(ffc->pts / (1000000)),
|
||||
// (int)(ffc->pts % 1000000), ffc->frame_number, ffc->frame_rate);
|
||||
//TRACE("FFDEC: PTS = %d:%d:%d.%d - ffc->frame_number = %ld "
|
||||
// "ffc->frame_rate = %ld\n", (int)(ffpicture->pts / (60*60*1000000)),
|
||||
// (int)(ffpicture->pts / (60*1000000)), (int)(ffpicture->pts / (1000000)),
|
||||
// (int)(ffpicture->pts % 1000000), ffc->frame_number, ffc->frame_rate);
|
||||
|
||||
if (len < 0) {
|
||||
printf("[%c] AVCodecDecoder: error in decoding frame %lld\n",
|
||||
isAudio?('a'):('v'), *out_frameCount);
|
||||
TRACE("[v] start_time=%02d:%02d.%02d field_sequence=%lu\n",
|
||||
int((mediaHeader->start_time / 60000000) % 60),
|
||||
int((mediaHeader->start_time / 1000000) % 60),
|
||||
int((mediaHeader->start_time / 10000) % 100),
|
||||
mediaHeader->u.raw_video.field_sequence);
|
||||
}
|
||||
|
||||
if (got_picture) {
|
||||
#ifdef DO_PROFILING
|
||||
prof_t2 = system_time();
|
||||
#if DO_PROFILING
|
||||
bigtime_t startTime = system_time();
|
||||
#endif
|
||||
|
||||
// NOTE: In the FFmpeg code example I've read, the length returned by
|
||||
// avcodec_decode_video() is completely ignored. Furthermore, the
|
||||
// packet buffers are supposed to contain complete frames only so we
|
||||
// don't seem to be required to buffer any packets because not the
|
||||
// complete packet has been read.
|
||||
int gotPicture = 0;
|
||||
int len = avcodec_decode_video(fContext, fInputPicture, &gotPicture,
|
||||
(uint8_t*)data, size);
|
||||
if (len < 0) {
|
||||
TRACE("[v] AVCodecDecoder: error in decoding frame %lld: %d\n",
|
||||
fFrame, len);
|
||||
// return B_ERROR;
|
||||
}
|
||||
|
||||
|
||||
//TRACE("FFDEC: PTS = %d:%d:%d.%d - fContext->frame_number = %ld "
|
||||
// "fContext->frame_rate = %ld\n", (int)(fContext->pts / (60*60*1000000)),
|
||||
// (int)(fContext->pts / (60*1000000)), (int)(fContext->pts / (1000000)),
|
||||
// (int)(fContext->pts % 1000000), fContext->frame_number,
|
||||
// fContext->frame_rate);
|
||||
//TRACE("FFDEC: PTS = %d:%d:%d.%d - fContext->frame_number = %ld "
|
||||
// "fContext->frame_rate = %ld\n",
|
||||
// (int)(fInputPicture->pts / (60*60*1000000)),
|
||||
// (int)(fInputPicture->pts / (60*1000000)),
|
||||
// (int)(fInputPicture->pts / (1000000)),
|
||||
// (int)(fInputPicture->pts % 1000000), fContext->frame_number,
|
||||
// fContext->frame_rate);
|
||||
|
||||
if (gotPicture) {
|
||||
#if DO_PROFILING
|
||||
bigtime_t formatConversionStart = system_time();
|
||||
#endif
|
||||
// TRACE("ONE FRAME OUT !! len=%d size=%ld (%s)\n", len, size,
|
||||
// pixfmt_to_string(ffc->pix_fmt));
|
||||
// pixfmt_to_string(fContext->pix_fmt));
|
||||
|
||||
// Some decoders do not set pix_fmt until they have decoded 1 frame
|
||||
if (conv_func == 0) {
|
||||
conv_func = resolve_colorspace(fOutputVideoFormat.display.format, ffc->pix_fmt);
|
||||
if (fFormatConversionFunc == NULL) {
|
||||
fFormatConversionFunc = resolve_colorspace(
|
||||
fOutputVideoFormat.display.format, fContext->pix_fmt);
|
||||
}
|
||||
opicture->data[0] = (uint8_t *)out_buffer;
|
||||
opicture->linesize[0] = fOutputVideoFormat.display.bytes_per_row;
|
||||
fOutputPicture->data[0] = (uint8_t*)outBuffer;
|
||||
fOutputPicture->linesize[0]
|
||||
= fOutputVideoFormat.display.bytes_per_row;
|
||||
|
||||
if (conv_func) {
|
||||
(*conv_func)(ffpicture, opicture,
|
||||
if (fFormatConversionFunc != NULL) {
|
||||
(*fFormatConversionFunc)(fInputPicture, fOutputPicture,
|
||||
fOutputVideoFormat.display.line_width,
|
||||
fOutputVideoFormat.display.line_count);
|
||||
}
|
||||
#ifdef DEBUG
|
||||
dump_ffframe(ffpicture, "ffpict");
|
||||
// dump_ffframe(opicture, "opict");
|
||||
dump_ffframe(fInputPicture, "ffpict");
|
||||
// dump_ffframe(fOutputPicture, "opict");
|
||||
#endif
|
||||
*out_frameCount = 1;
|
||||
*outFrameCount = 1;
|
||||
fFrame++;
|
||||
|
||||
#ifdef DO_PROFILING
|
||||
prof_t3 = system_time();
|
||||
diff1 += prof_t2 - prof_t1;
|
||||
diff2 += prof_t3 - prof_t2;
|
||||
prof_cnt++;
|
||||
#if DO_PROFILING
|
||||
bigtime_t doneTime = system_time();
|
||||
decodingTime += formatConversionStart - startTime;
|
||||
conversionTime += doneTime - formatConversionStart;
|
||||
profileCounter++;
|
||||
if (!(fFrame % 10)) {
|
||||
if (info) {
|
||||
TRACE("[%c] profile: d1 = %lld, d2 = %lld (%Ld) required %Ld\n",
|
||||
isAudio?('a'):('v'), diff1/prof_cnt, diff2/prof_cnt,
|
||||
TRACE("[v] profile: d1 = %lld, d2 = %lld (%Ld) required "
|
||||
"%Ld\n",
|
||||
decodingTime / profileCounter,
|
||||
conversionTime / profileCounter,
|
||||
fFrame, info->time_to_decode);
|
||||
} else {
|
||||
TRACE("[%c] profile: d1 = %lld, d2 = %lld (%Ld) required %Ld\n",
|
||||
isAudio?('a'):('v'), diff1/prof_cnt, diff2/prof_cnt,
|
||||
TRACE("[v] profile: d1 = %lld, d2 = %lld (%Ld) required "
|
||||
"%Ld\n",
|
||||
decodingTime / profileCounter,
|
||||
conversionTime / profileCounter,
|
||||
fFrame, bigtime_t(1000000LL / fOutputFrameRate));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
fStartTime = (bigtime_t) (1000000LL * fFrame / fOutputFrameRate);
|
||||
|
||||
return B_OK;
|
||||
} else {
|
||||
TRACE("frame %lld - no picture yet, len: %d, chunk size: %ld\n",
|
||||
fFrame, len, size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ public:
|
||||
const void* infoBuffer, size_t infoSize);
|
||||
|
||||
virtual status_t NegotiateOutputFormat(
|
||||
media_format* outputFormat);
|
||||
media_format* inOutFormat);
|
||||
|
||||
virtual status_t Decode(void* outBuffer, int64* outFrameCount,
|
||||
media_header* mediaHeader,
|
||||
@@ -43,31 +43,44 @@ public:
|
||||
bigtime_t* time);
|
||||
|
||||
|
||||
protected:
|
||||
private:
|
||||
status_t _NegotiateAudioOutputFormat(
|
||||
media_format* inOutFormat);
|
||||
|
||||
status_t _NegotiateVideoOutputFormat(
|
||||
media_format* inOutFormat);
|
||||
|
||||
status_t _DecodeAudio(void* outBuffer,
|
||||
int64* outFrameCount,
|
||||
media_header* mediaHeader,
|
||||
media_decode_info* info);
|
||||
|
||||
status_t _DecodeVideo(void* outBuffer,
|
||||
int64* outFrameCount,
|
||||
media_header* mediaHeader,
|
||||
media_decode_info* info);
|
||||
|
||||
|
||||
media_header fHeader;
|
||||
media_decode_info fInfo;
|
||||
|
||||
// friend class avCodecInputStream;
|
||||
|
||||
private:
|
||||
media_format fInputFormat;
|
||||
media_raw_video_format fOutputVideoFormat;
|
||||
|
||||
int64 fFrame;
|
||||
bool isAudio;
|
||||
bool fIsAudio;
|
||||
|
||||
int ffcodec_index_in_table;
|
||||
int fCodecIndexInTable;
|
||||
// helps to find codecpretty
|
||||
|
||||
// ffmpeg related datas
|
||||
// FFmpeg related members
|
||||
AVCodec* fCodec;
|
||||
AVCodecContext* ffc;
|
||||
AVFrame* ffpicture;
|
||||
AVFrame* opicture;
|
||||
AVCodecContext* fContext;
|
||||
AVFrame* fInputPicture;
|
||||
AVFrame* fOutputPicture;
|
||||
|
||||
bool fCodecInitDone;
|
||||
|
||||
gfx_convert_func conv_func; // colorspace convert func
|
||||
gfx_convert_func fFormatConversionFunc;
|
||||
|
||||
char* fExtraData;
|
||||
int fExtraDataSize;
|
||||
@@ -76,7 +89,8 @@ private:
|
||||
bigtime_t fStartTime;
|
||||
int32 fOutputFrameCount;
|
||||
float fOutputFrameRate;
|
||||
int fOutputFrameSize; // sample size * channel count
|
||||
int fOutputFrameSize;
|
||||
// sample size * channel count
|
||||
|
||||
const void* fChunkBuffer;
|
||||
int32 fChunkBufferOffset;
|
||||
|
||||
Reference in New Issue
Block a user