FFmpeg: Get frame decoding working

This commit is contained in:
Vicki Pfau 2020-07-10 01:10:32 -07:00
parent 390ed6c83c
commit 051fd94b70
2 changed files with 45 additions and 9 deletions

View File

@ -5,6 +5,8 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "ffmpeg-decoder.h" #include "ffmpeg-decoder.h"
#include <libswscale/swscale.h>
void FFmpegDecoderInit(struct FFmpegDecoder* decoder) { void FFmpegDecoderInit(struct FFmpegDecoder* decoder) {
#if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(58, 9, 100) #if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(58, 9, 100)
av_register_all(); av_register_all();
@ -79,14 +81,15 @@ bool FFmpegDecoderOpen(struct FFmpegDecoder* decoder, const char* infile) {
decoder->videoStream = i; decoder->videoStream = i;
decoder->width = context->coded_width; decoder->width = context->coded_width;
decoder->height = context->coded_height; decoder->height = context->coded_height;
if (decoder->d.videoDimensionsChanged) { if (decoder->out->videoDimensionsChanged) {
decoder->d.videoDimensionsChanged(&decoder->d, decoder->width, decoder->height); decoder->out->videoDimensionsChanged(decoder->out, decoder->width, decoder->height);
} }
#if LIBAVCODEC_VERSION_MAJOR >= 55 #if LIBAVCODEC_VERSION_MAJOR >= 55
decoder->videoFrame = av_frame_alloc(); decoder->videoFrame = av_frame_alloc();
#else #else
decoder->videoFrame = avcodec_alloc_frame(); decoder->videoFrame = avcodec_alloc_frame();
#endif #endif
decoder->pixels = malloc(decoder->width * decoder->height * BYTES_PER_PIXEL);
} }
if (type == AVMEDIA_TYPE_AUDIO) { if (type == AVMEDIA_TYPE_AUDIO) {
@ -111,8 +114,17 @@ void FFmpegDecoderClose(struct FFmpegDecoder* decoder) {
} }
if (decoder->audio) { if (decoder->audio) {
#ifdef FFMPEG_USE_CODECPAR
avcodec_free_context(&decoder->audio);
#else
avcodec_close(decoder->audio); avcodec_close(decoder->audio);
decoder->audio = NULL; decoder->audio = NULL;
#endif
}
if (decoder->scaleContext) {
sws_freeContext(decoder->scaleContext);
decoder->scaleContext = NULL;
} }
if (decoder->videoFrame) { if (decoder->videoFrame) {
@ -123,9 +135,18 @@ void FFmpegDecoderClose(struct FFmpegDecoder* decoder) {
#endif #endif
} }
if (decoder->pixels) {
free(decoder->pixels);
decoder->pixels = NULL;
}
if (decoder->video) { if (decoder->video) {
#ifdef FFMPEG_USE_CODECPAR
avcodec_free_context(&decoder->video);
#else
avcodec_close(decoder->video); avcodec_close(decoder->video);
decoder->video = NULL; decoder->video = NULL;
#endif
} }
if (decoder->context) { if (decoder->context) {
@ -138,28 +159,40 @@ bool FFmpegDecoderIsOpen(struct FFmpegDecoder* decoder) {
} }
bool FFmpegDecoderRead(struct FFmpegDecoder* decoder) { bool FFmpegDecoderRead(struct FFmpegDecoder* decoder) {
while (true) { bool readPacket = false;
while (!readPacket) {
AVPacket packet; AVPacket packet;
if (av_read_frame(decoder->context, &packet) < 0) { if (av_read_frame(decoder->context, &packet) < 0) {
return false; break;
} }
readPacket = true;
if (packet.stream_index == decoder->audioStream) { if (packet.stream_index == decoder->audioStream) {
// TODO
} else if (packet.stream_index == decoder->videoStream) { } else if (packet.stream_index == decoder->videoStream) {
#ifdef FFMPEG_USE_CODECPAR #ifdef FFMPEG_USE_CODECPAR
if (avcodec_send_packet(decoder->video, &packet) < 0) { if (avcodec_send_packet(decoder->video, &packet) < 0) {
// TODO
} }
if (avcodec_receive_frame(decoder->video, decoder->videoFrame) < 0) { if (avcodec_receive_frame(decoder->video, decoder->videoFrame) < 0) {
readPacket = false;
} }
#else #else
int gotData; int gotData;
if (avcodec_decode_video2(decoder->video, decoder->videoFrame, &gotData, &packet) < 0 || !gotData) { if (avcodec_decode_video2(decoder->video, decoder->videoFrame, &gotData, &packet) < 0 || !gotData) {
readPacket = false;
} }
#endif #endif
if (readPacket && decoder->out->postVideoFrame) {
if (!decoder->scaleContext) {
decoder->scaleContext = sws_getContext(decoder->width, decoder->height, decoder->videoFrame->format,
decoder->width, decoder->height, AV_PIX_FMT_BGR32,
SWS_POINT, 0, 0, 0);
}
int stride = decoder->width * BYTES_PER_PIXEL;
sws_scale(decoder->scaleContext, (const uint8_t* const*) decoder->videoFrame->data, decoder->videoFrame->linesize, 0, decoder->videoFrame->height, &decoder->pixels, &stride);
decoder->out->postVideoFrame(decoder->out, (const color_t*) decoder->pixels, decoder->width);
}
} }
#ifdef FFMPEG_USE_PACKET_UNREF #ifdef FFMPEG_USE_PACKET_UNREF
av_packet_unref(&packet); av_packet_unref(&packet);
@ -167,4 +200,5 @@ bool FFmpegDecoderRead(struct FFmpegDecoder* decoder) {
av_free_packet(&packet); av_free_packet(&packet);
#endif #endif
} }
return readPacket;
} }

View File

@ -17,7 +17,7 @@ CXX_GUARD_START
#define FFMPEG_DECODER_BUFSIZE 4096 #define FFMPEG_DECODER_BUFSIZE 4096
struct FFmpegDecoder { struct FFmpegDecoder {
struct mAVStream d; struct mAVStream* out;
struct AVFormatContext* context; struct AVFormatContext* context;
int audioStream; int audioStream;
@ -27,9 +27,11 @@ struct FFmpegDecoder {
int videoStream; int videoStream;
AVFrame* videoFrame; AVFrame* videoFrame;
struct AVCodecContext* video; struct AVCodecContext* video;
struct SwsContext* scaleContext;
int width; int width;
int height; int height;
uint8_t* pixels;
}; };
void FFmpegDecoderInit(struct FFmpegDecoder*); void FFmpegDecoderInit(struct FFmpegDecoder*);