FFMPEG plugin: Refactor video decoding function.

- Factor out the deinterlacing and color converting part to make the code more
  readable. This makes it easier to understand which code belongs to the actual
  decoding process and which code to the post processing.

- There seems to be no performance impact involved (I just looked at the spikes
  of the process manager) in factoring out this part, but one can always inline
  the method if a closer performance assesment (e.g. by enabling the profiling
  the existing profiling code) suggests so.

- Document the _DecodeVideo() method a little bit. Maybe someone can document
  the info parameter, as I'm a little bit clueless here.

- No functional change intended.

Signed-off-by: Colin Günther <[email protected]>
(cherry picked from commit c5fa095fa73d47e75a46cfc138a56028fcc01819)
This commit is contained in:
Colin Günther
2014-07-26 16:32:01 +02:00
parent a07d97ee3b
commit 0adda4f68f
2 changed files with 136 additions and 96 deletions
@@ -637,6 +637,23 @@ AVCodecDecoder::_DecodeAudio(void* _buffer, int64* outFrameCount,
}
/*! Fills the outBuffer with an already decoded video frame.
Besides the main duty described above, this method also fills out the other
output parameters as documented below.
@param outBuffer Pointer to the output buffer to copy the decoded video
frame to.
@param outFrameCount Pointer to the output variable to assign the number of
copied video frames (usually one video frame).
@param mediaHeader Pointer to the output media header that contains the
decoded video frame properties.
@param info TODO (not used at the moment)
@return B_OK Decoding a video frame succeeded.
@return B_LAST_BUFFER_ERROR There are no more video frames available.
@return other error codes
*/
status_t
AVCodecDecoder::_DecodeVideo(void* outBuffer, int64* outFrameCount,
media_header* mediaHeader, media_decode_info* info)
@@ -757,109 +774,14 @@ AVCodecDecoder::_DecodeNextVideoFrame()
// fContext->frame_rate);
if (gotPicture) {
int width = fOutputVideoFormat.display.line_width;
int height = fOutputVideoFormat.display.line_count;
AVPicture deinterlacedPicture;
bool useDeinterlacedPicture = false;
if (fRawDecodedPicture->interlaced_frame) {
AVPicture rawPicture;
rawPicture.data[0] = fRawDecodedPicture->data[0];
rawPicture.data[1] = fRawDecodedPicture->data[1];
rawPicture.data[2] = fRawDecodedPicture->data[2];
rawPicture.data[3] = fRawDecodedPicture->data[3];
rawPicture.linesize[0] = fRawDecodedPicture->linesize[0];
rawPicture.linesize[1] = fRawDecodedPicture->linesize[1];
rawPicture.linesize[2] = fRawDecodedPicture->linesize[2];
rawPicture.linesize[3] = fRawDecodedPicture->linesize[3];
avpicture_alloc(&deinterlacedPicture,
fContext->pix_fmt, width, height);
if (avpicture_deinterlace(&deinterlacedPicture, &rawPicture,
fContext->pix_fmt, width, height) < 0) {
TRACE("[v] avpicture_deinterlace() - error\n");
} else
useDeinterlacedPicture = true;
}
#if DO_PROFILING
bigtime_t formatConversionStart = system_time();
#endif
// TRACE("ONE FRAME OUT !! len=%d size=%ld (%s)\n", len, size,
// pixfmt_to_string(fContext->pix_fmt));
// Some decoders do not set pix_fmt until they have decoded 1 frame
#if USE_SWS_FOR_COLOR_SPACE_CONVERSION
if (fSwsContext == NULL) {
fSwsContext = sws_getContext(fContext->width, fContext->height,
fContext->pix_fmt, fContext->width, fContext->height,
colorspace_to_pixfmt(fOutputVideoFormat.display.format),
SWS_FAST_BILINEAR, NULL, NULL, NULL);
}
#else
if (fFormatConversionFunc == NULL) {
fFormatConversionFunc = resolve_colorspace(
fOutputVideoFormat.display.format, fContext->pix_fmt,
fContext->width, fContext->height);
}
#endif
_DeinterlaceAndColorConvertVideoFrame();
fDecodedDataSizeInBytes = avpicture_get_size(
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;
#if USE_SWS_FOR_COLOR_SPACE_CONVERSION
if (fSwsContext != NULL) {
#else
if (fFormatConversionFunc != NULL) {
#endif
if (useDeinterlacedPicture) {
AVFrame deinterlacedFrame;
deinterlacedFrame.data[0] = deinterlacedPicture.data[0];
deinterlacedFrame.data[1] = deinterlacedPicture.data[1];
deinterlacedFrame.data[2] = deinterlacedPicture.data[2];
deinterlacedFrame.data[3] = deinterlacedPicture.data[3];
deinterlacedFrame.linesize[0]
= deinterlacedPicture.linesize[0];
deinterlacedFrame.linesize[1]
= deinterlacedPicture.linesize[1];
deinterlacedFrame.linesize[2]
= deinterlacedPicture.linesize[2];
deinterlacedFrame.linesize[3]
= deinterlacedPicture.linesize[3];
#if USE_SWS_FOR_COLOR_SPACE_CONVERSION
sws_scale(fSwsContext, deinterlacedFrame.data,
deinterlacedFrame.linesize, 0, fContext->height,
fPostProcessedDecodedPicture->data,
fPostProcessedDecodedPicture->linesize);
#else
(*fFormatConversionFunc)(&deinterlacedFrame,
fPostProcessedDecodedPicture, width, height);
#endif
} else {
#if USE_SWS_FOR_COLOR_SPACE_CONVERSION
sws_scale(fSwsContext, fRawDecodedPicture->data,
fRawDecodedPicture->linesize, 0, fContext->height,
fPostProcessedDecodedPicture->data,
fPostProcessedDecodedPicture->linesize);
#else
(*fFormatConversionFunc)(fRawDecodedPicture,
fPostProcessedDecodedPicture, width, height);
#endif
}
}
if (fRawDecodedPicture->interlaced_frame)
avpicture_free(&deinterlacedPicture);
#ifdef DEBUG
dump_ffframe(fRawDecodedPicture, "ffpict");
// dump_ffframe(fPostProcessedDecodedPicture, "opict");
@@ -897,3 +819,120 @@ AVCodecDecoder::_DecodeNextVideoFrame()
}
}
}
/*! This function applies deinterlacing (only if needed) and color conversion
to the video frame in fRawDecodedPicture.
It is assumed that fRawDecodedPicture wasn't deinterlaced and color
converted yet (otherwise this function behaves in unknown manners).
You should only call this function in _DecodeNextVideoFrame() when we
got a new picture decoded by the video decoder.
When this function finishes the postprocessed video frame will be available
in fPostProcessedDecodedPicture and fDecodedData (fDecodedDataSizeInBytes
will be set accordingly).
*/
void
AVCodecDecoder::_DeinterlaceAndColorConvertVideoFrame()
{
int width = fOutputVideoFormat.display.line_width;
int height = fOutputVideoFormat.display.line_count;
AVPicture deinterlacedPicture;
bool useDeinterlacedPicture = false;
if (fRawDecodedPicture->interlaced_frame) {
AVPicture rawPicture;
rawPicture.data[0] = fRawDecodedPicture->data[0];
rawPicture.data[1] = fRawDecodedPicture->data[1];
rawPicture.data[2] = fRawDecodedPicture->data[2];
rawPicture.data[3] = fRawDecodedPicture->data[3];
rawPicture.linesize[0] = fRawDecodedPicture->linesize[0];
rawPicture.linesize[1] = fRawDecodedPicture->linesize[1];
rawPicture.linesize[2] = fRawDecodedPicture->linesize[2];
rawPicture.linesize[3] = fRawDecodedPicture->linesize[3];
avpicture_alloc(&deinterlacedPicture,
fContext->pix_fmt, width, height);
if (avpicture_deinterlace(&deinterlacedPicture, &rawPicture,
fContext->pix_fmt, width, height) < 0) {
TRACE("[v] avpicture_deinterlace() - error\n");
} else
useDeinterlacedPicture = true;
}
// Some decoders do not set pix_fmt until they have decoded 1 frame
#if USE_SWS_FOR_COLOR_SPACE_CONVERSION
if (fSwsContext == NULL) {
fSwsContext = sws_getContext(fContext->width, fContext->height,
fContext->pix_fmt, fContext->width, fContext->height,
colorspace_to_pixfmt(fOutputVideoFormat.display.format),
SWS_FAST_BILINEAR, NULL, NULL, NULL);
}
#else
if (fFormatConversionFunc == NULL) {
fFormatConversionFunc = resolve_colorspace(
fOutputVideoFormat.display.format, fContext->pix_fmt,
fContext->width, fContext->height);
}
#endif
fDecodedDataSizeInBytes = avpicture_get_size(
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;
#if USE_SWS_FOR_COLOR_SPACE_CONVERSION
if (fSwsContext != NULL) {
#else
if (fFormatConversionFunc != NULL) {
#endif
if (useDeinterlacedPicture) {
AVFrame deinterlacedFrame;
deinterlacedFrame.data[0] = deinterlacedPicture.data[0];
deinterlacedFrame.data[1] = deinterlacedPicture.data[1];
deinterlacedFrame.data[2] = deinterlacedPicture.data[2];
deinterlacedFrame.data[3] = deinterlacedPicture.data[3];
deinterlacedFrame.linesize[0]
= deinterlacedPicture.linesize[0];
deinterlacedFrame.linesize[1]
= deinterlacedPicture.linesize[1];
deinterlacedFrame.linesize[2]
= deinterlacedPicture.linesize[2];
deinterlacedFrame.linesize[3]
= deinterlacedPicture.linesize[3];
#if USE_SWS_FOR_COLOR_SPACE_CONVERSION
sws_scale(fSwsContext, deinterlacedFrame.data,
deinterlacedFrame.linesize, 0, fContext->height,
fPostProcessedDecodedPicture->data,
fPostProcessedDecodedPicture->linesize);
#else
(*fFormatConversionFunc)(&deinterlacedFrame,
fPostProcessedDecodedPicture, width, height);
#endif
} else {
#if USE_SWS_FOR_COLOR_SPACE_CONVERSION
sws_scale(fSwsContext, fRawDecodedPicture->data,
fRawDecodedPicture->linesize, 0, fContext->height,
fPostProcessedDecodedPicture->data,
fPostProcessedDecodedPicture->linesize);
#else
(*fFormatConversionFunc)(fRawDecodedPicture,
fPostProcessedDecodedPicture, width, height);
#endif
}
}
if (fRawDecodedPicture->interlaced_frame)
avpicture_free(&deinterlacedPicture);
}
@@ -65,6 +65,7 @@ private:
media_decode_info* info);
status_t _DecodeNextVideoFrame();
void _DeinterlaceAndColorConvertVideoFrame();
media_header fHeader;