FFMPEG plugin: Refactor video decoding function.

- We factor out the code that does the decoding, deinterlacing and color space
  converting into its own function. This prepares auto detection of video frame
  properties in a later commit. Auto detection means (for example), that you
  don't need to know the size of the decoded video frame -before- intitializing
  the video codec as it is the case with the current implementation.

- Use the already existent private member variable fHeader to fill out and
  return video frame properties.

- Rename some variables to be more self describing.

- No functional change intended.

Signed-off-by: Colin Günther <coling@gmx.de>
(cherry picked from commit 6beab04f48e98022041895750f38c5a35a5f4f9e)
This commit is contained in:
Colin Günther 2014-07-15 15:33:06 +02:00
parent 29da3b5548
commit 172c55faf1
2 changed files with 123 additions and 66 deletions

View File

@ -80,8 +80,10 @@ AVCodecDecoder::AVCodecDecoder()
fIsAudio(false), fIsAudio(false),
fCodec(NULL), fCodec(NULL),
fContext(avcodec_alloc_context3(NULL)), fContext(avcodec_alloc_context3(NULL)),
fInputPicture(avcodec_alloc_frame()), fDecodedData(NULL),
fOutputPicture(avcodec_alloc_frame()), fDecodedDataSizeInBytes(0),
fPostProcessedDecodedPicture(avcodec_alloc_frame()),
fRawDecodedPicture(avcodec_alloc_frame()),
fCodecInitDone(false), fCodecInitDone(false),
@ -135,8 +137,10 @@ AVCodecDecoder::~AVCodecDecoder()
if (fCodecInitDone) if (fCodecInitDone)
avcodec_close(fContext); avcodec_close(fContext);
av_free(fOutputPicture); free(fDecodedData);
av_free(fInputPicture);
av_free(fPostProcessedDecodedPicture);
av_free(fRawDecodedPicture);
av_free(fContext); av_free(fContext);
av_free(fOutputFrame); av_free(fOutputFrame);
@ -256,6 +260,7 @@ AVCodecDecoder::SeekedTo(int64 frame, bigtime_t time)
fChunkBufferSize = 0; fChunkBufferSize = 0;
fOutputBufferOffset = 0; fOutputBufferOffset = 0;
fOutputBufferSize = 0; fOutputBufferSize = 0;
fDecodedDataSizeInBytes = 0;
fFrame = frame; fFrame = frame;
fStartTime = time; fStartTime = time;
@ -635,6 +640,43 @@ AVCodecDecoder::_DecodeAudio(void* _buffer, int64* outFrameCount,
status_t status_t
AVCodecDecoder::_DecodeVideo(void* outBuffer, int64* outFrameCount, AVCodecDecoder::_DecodeVideo(void* outBuffer, int64* outFrameCount,
media_header* mediaHeader, media_decode_info* info) media_header* mediaHeader, media_decode_info* info)
{
status_t videoDecodingStatus
= fDecodedDataSizeInBytes > 0 ? B_OK : _DecodeNextVideoFrame();
if (videoDecodingStatus != B_OK)
return videoDecodingStatus;
*outFrameCount = 1;
*mediaHeader = fHeader;
memcpy(outBuffer, fDecodedData, fDecodedDataSizeInBytes);
fDecodedDataSizeInBytes = 0;
return B_OK;
}
/*! Decode next video frame
We decode exactly one video frame into fDecodedData. To achieve this goal,
we might need to request several chunks of encoded data resulting in a
variable execution time of this function.
The length of the decoded video frame is stored in
fDecodedDataSizeInBytes. If this variable is greater than zero, you can
assert that there is a valid video frame available in fDecodedData.
The decoded video frame in fDecodedData has color space conversion and
deinterlacing already applied.
To every decoded video frame there is a media_header populated in
fHeader, containing the corresponding video frame properties.
@return B_OK, when we successfully decoded one video frame
*/
status_t
AVCodecDecoder::_DecodeNextVideoFrame()
{ {
bool firstRun = true; bool firstRun = true;
while (true) { while (true) {
@ -658,24 +700,24 @@ AVCodecDecoder::_DecodeVideo(void* outBuffer, int64* outFrameCount,
if (firstRun) { if (firstRun) {
firstRun = false; firstRun = false;
mediaHeader->type = B_MEDIA_RAW_VIDEO; fHeader.type = B_MEDIA_RAW_VIDEO;
mediaHeader->start_time = chunkMediaHeader.start_time; fHeader.start_time = chunkMediaHeader.start_time;
fStartTime = chunkMediaHeader.start_time; fStartTime = chunkMediaHeader.start_time;
mediaHeader->file_pos = 0; fHeader.file_pos = 0;
mediaHeader->orig_size = 0; fHeader.orig_size = 0;
mediaHeader->u.raw_video.field_gamma = 1.0; fHeader.u.raw_video.field_gamma = 1.0;
mediaHeader->u.raw_video.field_sequence = fFrame; fHeader.u.raw_video.field_sequence = fFrame;
mediaHeader->u.raw_video.field_number = 0; fHeader.u.raw_video.field_number = 0;
mediaHeader->u.raw_video.pulldown_number = 0; fHeader.u.raw_video.pulldown_number = 0;
mediaHeader->u.raw_video.first_active_line = 1; fHeader.u.raw_video.first_active_line = 1;
mediaHeader->u.raw_video.line_count fHeader.u.raw_video.line_count
= fOutputVideoFormat.display.line_count; = fOutputVideoFormat.display.line_count;
TRACE("[v] start_time=%02d:%02d.%02d field_sequence=%lu\n", TRACE("[v] start_time=%02d:%02d.%02d field_sequence=%lu\n",
int((mediaHeader->start_time / 60000000) % 60), int((fHeader.start_time / 60000000) % 60),
int((mediaHeader->start_time / 1000000) % 60), int((fHeader.start_time / 1000000) % 60),
int((mediaHeader->start_time / 10000) % 100), int((fHeader.start_time / 10000) % 100),
mediaHeader->u.raw_video.field_sequence); fHeader.u.raw_video.field_sequence);
} }
#if DO_PROFILING #if DO_PROFILING
@ -690,8 +732,8 @@ AVCodecDecoder::_DecodeVideo(void* outBuffer, int64* outFrameCount,
fTempPacket.data = (uint8_t*)fChunkBuffer; fTempPacket.data = (uint8_t*)fChunkBuffer;
fTempPacket.size = fChunkBufferSize; fTempPacket.size = fChunkBufferSize;
int gotPicture = 0; int gotPicture = 0;
int len = avcodec_decode_video2(fContext, fInputPicture, &gotPicture, int len = avcodec_decode_video2(fContext, fRawDecodedPicture,
&fTempPacket); &gotPicture, &fTempPacket);
if (len < 0) { if (len < 0) {
TRACE("[v] AVCodecDecoder: error in decoding frame %lld: %d\n", TRACE("[v] AVCodecDecoder: error in decoding frame %lld: %d\n",
fFrame, len); fFrame, len);
@ -708,10 +750,10 @@ AVCodecDecoder::_DecodeVideo(void* outBuffer, int64* outFrameCount,
// fContext->frame_rate); // fContext->frame_rate);
//TRACE("FFDEC: PTS = %d:%d:%d.%d - fContext->frame_number = %ld " //TRACE("FFDEC: PTS = %d:%d:%d.%d - fContext->frame_number = %ld "
// "fContext->frame_rate = %ld\n", // "fContext->frame_rate = %ld\n",
// (int)(fInputPicture->pts / (60*60*1000000)), // (int)(fRawDecodedPicture->pts / (60*60*1000000)),
// (int)(fInputPicture->pts / (60*1000000)), // (int)(fRawDecodedPicture->pts / (60*1000000)),
// (int)(fInputPicture->pts / (1000000)), // (int)(fRawDecodedPicture->pts / (1000000)),
// (int)(fInputPicture->pts % 1000000), fContext->frame_number, // (int)(fRawDecodedPicture->pts % 1000000), fContext->frame_number,
// fContext->frame_rate); // fContext->frame_rate);
if (gotPicture) { if (gotPicture) {
@ -720,21 +762,21 @@ AVCodecDecoder::_DecodeVideo(void* outBuffer, int64* outFrameCount,
AVPicture deinterlacedPicture; AVPicture deinterlacedPicture;
bool useDeinterlacedPicture = false; bool useDeinterlacedPicture = false;
if (fInputPicture->interlaced_frame) { if (fRawDecodedPicture->interlaced_frame) {
AVPicture source; AVPicture rawPicture;
source.data[0] = fInputPicture->data[0]; rawPicture.data[0] = fRawDecodedPicture->data[0];
source.data[1] = fInputPicture->data[1]; rawPicture.data[1] = fRawDecodedPicture->data[1];
source.data[2] = fInputPicture->data[2]; rawPicture.data[2] = fRawDecodedPicture->data[2];
source.data[3] = fInputPicture->data[3]; rawPicture.data[3] = fRawDecodedPicture->data[3];
source.linesize[0] = fInputPicture->linesize[0]; rawPicture.linesize[0] = fRawDecodedPicture->linesize[0];
source.linesize[1] = fInputPicture->linesize[1]; rawPicture.linesize[1] = fRawDecodedPicture->linesize[1];
source.linesize[2] = fInputPicture->linesize[2]; rawPicture.linesize[2] = fRawDecodedPicture->linesize[2];
source.linesize[3] = fInputPicture->linesize[3]; rawPicture.linesize[3] = fRawDecodedPicture->linesize[3];
avpicture_alloc(&deinterlacedPicture, avpicture_alloc(&deinterlacedPicture,
fContext->pix_fmt, width, height); fContext->pix_fmt, width, height);
if (avpicture_deinterlace(&deinterlacedPicture, &source, if (avpicture_deinterlace(&deinterlacedPicture, &rawPicture,
fContext->pix_fmt, width, height) < 0) { fContext->pix_fmt, width, height) < 0) {
TRACE("[v] avpicture_deinterlace() - error\n"); TRACE("[v] avpicture_deinterlace() - error\n");
} else } else
@ -763,8 +805,16 @@ AVCodecDecoder::_DecodeVideo(void* outBuffer, int64* outFrameCount,
} }
#endif #endif
fOutputPicture->data[0] = (uint8_t*)outBuffer; fDecodedDataSizeInBytes = avpicture_get_size(
fOutputPicture->linesize[0] colorspace_to_pixfmt(fOutputVideoFormat.display.format),
fContext->width, fContext->height);
if (fDecodedData == NULL)
fDecodedData
= static_cast<uint8_t*>(malloc(fDecodedDataSizeInBytes));
fPostProcessedDecodedPicture->data[0] = fDecodedData;
fPostProcessedDecodedPicture->linesize[0]
= fOutputVideoFormat.display.bytes_per_row; = fOutputVideoFormat.display.bytes_per_row;
#if USE_SWS_FOR_COLOR_SPACE_CONVERSION #if USE_SWS_FOR_COLOR_SPACE_CONVERSION
@ -773,42 +823,47 @@ AVCodecDecoder::_DecodeVideo(void* outBuffer, int64* outFrameCount,
if (fFormatConversionFunc != NULL) { if (fFormatConversionFunc != NULL) {
#endif #endif
if (useDeinterlacedPicture) { if (useDeinterlacedPicture) {
AVFrame inputFrame; AVFrame deinterlacedFrame;
inputFrame.data[0] = deinterlacedPicture.data[0]; deinterlacedFrame.data[0] = deinterlacedPicture.data[0];
inputFrame.data[1] = deinterlacedPicture.data[1]; deinterlacedFrame.data[1] = deinterlacedPicture.data[1];
inputFrame.data[2] = deinterlacedPicture.data[2]; deinterlacedFrame.data[2] = deinterlacedPicture.data[2];
inputFrame.data[3] = deinterlacedPicture.data[3]; deinterlacedFrame.data[3] = deinterlacedPicture.data[3];
inputFrame.linesize[0] = deinterlacedPicture.linesize[0]; deinterlacedFrame.linesize[0]
inputFrame.linesize[1] = deinterlacedPicture.linesize[1]; = deinterlacedPicture.linesize[0];
inputFrame.linesize[2] = deinterlacedPicture.linesize[2]; deinterlacedFrame.linesize[1]
inputFrame.linesize[3] = deinterlacedPicture.linesize[3]; = deinterlacedPicture.linesize[1];
deinterlacedFrame.linesize[2]
= deinterlacedPicture.linesize[2];
deinterlacedFrame.linesize[3]
= deinterlacedPicture.linesize[3];
#if USE_SWS_FOR_COLOR_SPACE_CONVERSION #if USE_SWS_FOR_COLOR_SPACE_CONVERSION
sws_scale(fSwsContext, inputFrame.data, sws_scale(fSwsContext, deinterlacedFrame.data,
inputFrame.linesize, 0, fContext->height, deinterlacedFrame.linesize, 0, fContext->height,
fOutputPicture->data, fOutputPicture->linesize); fPostProcessedDecodedPicture->data,
fPostProcessedDecodedPicture->linesize);
#else #else
(*fFormatConversionFunc)(&inputFrame, (*fFormatConversionFunc)(&deinterlacedFrame,
fOutputPicture, width, height); fPostProcessedDecodedPicture, width, height);
#endif #endif
} else { } else {
#if USE_SWS_FOR_COLOR_SPACE_CONVERSION #if USE_SWS_FOR_COLOR_SPACE_CONVERSION
sws_scale(fSwsContext, fInputPicture->data, sws_scale(fSwsContext, fRawDecodedPicture->data,
fInputPicture->linesize, 0, fContext->height, fRawDecodedPicture->linesize, 0, fContext->height,
fOutputPicture->data, fOutputPicture->linesize); fPostProcessedDecodedPicture->data,
fPostProcessedDecodedPicture->linesize);
#else #else
(*fFormatConversionFunc)(fInputPicture, fOutputPicture, (*fFormatConversionFunc)(fRawDecodedPicture,
width, height); fPostProcessedDecodedPicture, width, height);
#endif #endif
} }
} }
if (fInputPicture->interlaced_frame) if (fRawDecodedPicture->interlaced_frame)
avpicture_free(&deinterlacedPicture); avpicture_free(&deinterlacedPicture);
#ifdef DEBUG #ifdef DEBUG
dump_ffframe(fInputPicture, "ffpict"); dump_ffframe(fRawDecodedPicture, "ffpict");
// dump_ffframe(fOutputPicture, "opict"); // dump_ffframe(fPostProcessedDecodedPicture, "opict");
#endif #endif
*outFrameCount = 1;
fFrame++; fFrame++;
#if DO_PROFILING #if DO_PROFILING
@ -842,5 +897,3 @@ AVCodecDecoder::_DecodeVideo(void* outBuffer, int64* outFrameCount,
} }
} }
} }

View File

@ -64,6 +64,8 @@ private:
media_header* mediaHeader, media_header* mediaHeader,
media_decode_info* info); media_decode_info* info);
status_t _DecodeNextVideoFrame();
media_header fHeader; media_header fHeader;
media_format fInputFormat; media_format fInputFormat;
@ -75,8 +77,10 @@ private:
// FFmpeg related members // FFmpeg related members
AVCodec* fCodec; AVCodec* fCodec;
AVCodecContext* fContext; AVCodecContext* fContext;
AVFrame* fInputPicture; uint8_t* fDecodedData;
AVFrame* fOutputPicture; size_t fDecodedDataSizeInBytes;
AVFrame* fPostProcessedDecodedPicture;
AVFrame* fRawDecodedPicture;
bool fCodecInitDone; bool fCodecInitDone;