* 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:
Stephan Aßmus
2009-07-08 09:43:06 +00:00
parent 0c4d88d353
commit 12a9eb5d93
2 changed files with 507 additions and 418 deletions
@@ -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;