diff --git a/src/add-ons/media/plugins/ffmpeg/AVCodecDecoder.cpp b/src/add-ons/media/plugins/ffmpeg/AVCodecDecoder.cpp index f74e44492c..4f85762405 100644 --- a/src/add-ons/media/plugins/ffmpeg/AVCodecDecoder.cpp +++ b/src/add-ons/media/plugins/ffmpeg/AVCodecDecoder.cpp @@ -22,6 +22,7 @@ #include #include +#include #include "Utilities.h" @@ -126,6 +127,13 @@ AVCodecDecoder::AVCodecDecoder() fDecodedDataBuffer(av_frame_alloc()), fDecodedDataBufferOffset(0), fDecodedDataBufferSize(0) +#if LIBAVCODEC_VERSION_INT >= ((57 << 16) | (0 << 8)) + , + fBufferSinkContext(NULL), + fBufferSourceContext(NULL), + fFilterGraph(NULL), + fFilterFrame(NULL) +#endif { TRACE("AVCodecDecoder::AVCodecDecoder()\n"); @@ -164,6 +172,11 @@ AVCodecDecoder::~AVCodecDecoder() av_free(fContext); av_free(fDecodedDataBuffer); +#if LIBAVCODEC_VERSION_INT >= ((57 << 16) | (0 << 8)) + av_frame_free(&fFilterFrame); + avfilter_graph_free(&fFilterGraph); +#endif + #if USE_SWS_FOR_COLOR_SPACE_CONVERSION if (fSwsContext != NULL) sws_freeContext(fSwsContext); @@ -1641,9 +1654,10 @@ AVCodecDecoder::_DeinterlaceAndColorConvertVideoFrame() } else useDeinterlacedPicture = true; #else - // avpicture_deinterlace is gone - // TODO: implement alternate deinterlace using avfilter - TRACE("[v] avpicture_deinterlace() - not implemented\n"); + // deinterlace implemented using avfilter + _ProcessFilterGraph(&deinterlacedPicture, &rawPicture, + fContext->pix_fmt, displayWidth, displayHeight); + useDeinterlacedPicture = true; #endif } @@ -1723,3 +1737,101 @@ AVCodecDecoder::_DeinterlaceAndColorConvertVideoFrame() return B_OK; } + + +#if LIBAVCODEC_VERSION_INT >= ((57 << 16) | (0 << 8)) + +/*! \brief Init the deinterlace filter graph. + + \returns B_OK the filter graph could be built. + \returns B_BAD_VALUE something was wrong with building the graph. +*/ +status_t +AVCodecDecoder::_InitFilterGraph(enum AVPixelFormat pixfmt, int32 width, + int32 height) +{ + if (fFilterGraph != NULL) { + av_frame_free(&fFilterFrame); + avfilter_graph_free(&fFilterGraph); + } + + fFilterGraph = avfilter_graph_alloc(); + + BString arguments; + arguments.SetToFormat("buffer=video_size=%dx%d:pix_fmt=%d:time_base=1/1:" + "pixel_aspect=0/1[in];[in]yadif[out];[out]buffersink", width, height, + pixfmt); + AVFilterInOut* inputs = NULL; + AVFilterInOut* outputs = NULL; + TRACE("[v] _InitFilterGraph(): %s\n", arguments.String()); + int ret = avfilter_graph_parse2(fFilterGraph, arguments.String(), &inputs, + &outputs); + if (ret < 0) { + fprintf(stderr, "avfilter_graph_parse2() failed\n"); + return B_BAD_VALUE; + } + + ret = avfilter_graph_config(fFilterGraph, NULL); + if (ret < 0) { + fprintf(stderr, "avfilter_graph_config() failed\n"); + return B_BAD_VALUE; + } + + fBufferSourceContext = avfilter_graph_get_filter(fFilterGraph, + "Parsed_buffer_0"); + fBufferSinkContext = avfilter_graph_get_filter(fFilterGraph, + "Parsed_buffersink_2"); + if (fBufferSourceContext == NULL || fBufferSinkContext == NULL) { + fprintf(stderr, "avfilter_graph_get_filter() failed\n"); + return B_BAD_VALUE; + } + fFilterFrame = av_frame_alloc(); + fLastWidth = width; + fLastHeight = height; + fLastPixfmt = pixfmt; + + return B_OK; +} + + +/*! \brief Process an AVPicture with the deinterlace filter graph. + + We decode exactly one video frame into dst. + Equivalent function for avpicture_deinterlace() from version 2.x. + + \returns B_OK video frame successfully deinterlaced. + \returns B_BAD_DATA No frame could be output. + \returns B_NO_MEMORY Not enough memory available for correct operation. +*/ +status_t +AVCodecDecoder::_ProcessFilterGraph(AVPicture *dst, const AVPicture *src, + enum AVPixelFormat pixfmt, int32 width, int32 height) +{ + if (fFilterGraph == NULL || width != fLastWidth + || height != fLastHeight || pixfmt != fLastPixfmt) { + + status_t err = _InitFilterGraph(pixfmt, width, height); + if (err != B_OK) + return err; + } + + memcpy(fFilterFrame->data, src->data, sizeof(src->data)); + memcpy(fFilterFrame->linesize, src->linesize, sizeof(src->linesize)); + fFilterFrame->width = width; + fFilterFrame->height = height; + fFilterFrame->format = pixfmt; + + int ret = av_buffersrc_add_frame(fBufferSourceContext, fFilterFrame); + if (ret < 0) + return B_NO_MEMORY; + + ret = av_buffersink_get_frame(fBufferSinkContext, fFilterFrame); + if (ret < 0) + return B_BAD_DATA; + + av_picture_copy(dst, (const AVPicture *)fFilterFrame, pixfmt, width, + height); + av_frame_unref(fFilterFrame); + return B_OK; +} +#endif diff --git a/src/add-ons/media/plugins/ffmpeg/AVCodecDecoder.h b/src/add-ons/media/plugins/ffmpeg/AVCodecDecoder.h index b839d52348..b2978cb502 100644 --- a/src/add-ons/media/plugins/ffmpeg/AVCodecDecoder.h +++ b/src/add-ons/media/plugins/ffmpeg/AVCodecDecoder.h @@ -19,6 +19,11 @@ extern "C" { #include "avcodec.h" +#if LIBAVCODEC_VERSION_INT >= ((57 << 16) | (0 << 8)) + #include "avfilter.h" + #include "buffersink.h" + #include "buffersrc.h" +#endif #include "swresample.h" #include "swscale.h" } @@ -95,6 +100,14 @@ private: void _UpdateMediaHeaderForVideoFrame(); status_t _DeinterlaceAndColorConvertVideoFrame(); +#if LIBAVCODEC_VERSION_INT >= ((57 << 16) | (0 << 8)) + // video deinterlace filter graph + status_t _InitFilterGraph(enum AVPixelFormat pixfmt, + int32 width, int32 height); + status_t _ProcessFilterGraph(AVPicture *dst, + const AVPicture *src, enum AVPixelFormat pixfmt, + int32 width, int32 height); +#endif media_header fHeader; // Contains the properties of the current @@ -144,6 +157,17 @@ private: int32 fDecodedDataBufferSize; AVPacket fTempPacket; + +#if LIBAVCODEC_VERSION_INT >= ((57 << 16) | (0 << 8)) + // video deinterlace feature + AVFilterContext* fBufferSinkContext; + AVFilterContext* fBufferSourceContext; + AVFilterGraph* fFilterGraph; + AVFrame* fFilterFrame; + int32 fLastWidth; + int32 fLastHeight; + enum AVPixelFormat fLastPixfmt; +#endif }; #endif // AVCODEC_DECODER_H diff --git a/src/add-ons/media/plugins/ffmpeg/FFmpegPlugin.cpp b/src/add-ons/media/plugins/ffmpeg/FFmpegPlugin.cpp index 8752486a0c..83697b41bc 100644 --- a/src/add-ons/media/plugins/ffmpeg/FFmpegPlugin.cpp +++ b/src/add-ons/media/plugins/ffmpeg/FFmpegPlugin.cpp @@ -87,6 +87,9 @@ FFmpegPlugin::GlobalInitilizer::GlobalInitilizer() av_register_all(); // This will also call av_codec_init() by registering codecs. +#if LIBAVCODEC_VERSION_INT >= ((57 << 16) | (0 << 8)) + avfilter_register_all(); +#endif }