Video: use libswscale to handle video format conversion

This commit is contained in:
Jeffrey Pfau 2014-10-28 02:17:18 -07:00
parent 9c83462343
commit 3878e4b196
3 changed files with 30 additions and 32 deletions

View File

@ -82,7 +82,7 @@ add_definitions(-DBINARY_NAME="${BINARY_NAME}" -DPROJECT_NAME="${PROJECT_NAME}"
# Feature dependencies
find_feature(USE_CLI_DEBUGGER "libedit")
find_feature(USE_FFMPEG "libavcodec;libavformat;libavresample;libavutil")
find_feature(USE_FFMPEG "libavcodec;libavformat;libavresample;libavutil;libswscale")
find_feature(USE_PNG "ZLIB;PNG")
find_feature(USE_LIBZIP "libzip")
@ -135,10 +135,10 @@ source_group("ARM debugger" FILES ${DEBUGGER_SRC})
if(USE_FFMPEG)
add_definitions(-DUSE_FFMPEG)
include_directories(AFTER ${LIBAVCODEC_INCLUDE_DIRS} ${LIBAVFORMAT_INCLUDE_DIRS} ${LIBAVRESAMPLE_INCLUDE_DIRS} ${LIBAVUTIL_INCLUDE_DIRS})
link_directories(${LIBAVCODEC_LIBRARY_DIRS} ${LIBAVFORMAT_LIBRARY_DIRS} ${LIBAVRESAMPLE_LIBRARY_DIRS} ${LIBAVUTIL_LIBRARY_DIRS})
include_directories(AFTER ${LIBAVCODEC_INCLUDE_DIRS} ${LIBAVFORMAT_INCLUDE_DIRS} ${LIBAVRESAMPLE_INCLUDE_DIRS} ${LIBAVUTIL_INCLUDE_DIRS} ${LIBSWSCALE_INCLUDE_DIRS})
link_directories(${LIBAVCODEC_LIBRARY_DIRS} ${LIBAVFORMAT_LIBRARY_DIRS} ${LIBAVRESAMPLE_LIBRARY_DIRS} ${LIBAVUTIL_LIBRARY_DIRS} ${LIBSWSCALE_LIBRARY_DIRS})
list(APPEND UTIL_SRC "${CMAKE_SOURCE_DIR}/src/platform/ffmpeg/ffmpeg-encoder.c")
list(APPEND DEPENDENCY_LIB ${LIBAVCODEC_LIBRARIES} ${LIBAVFORMAT_LIBRARIES} ${LIBAVRESAMPLE_LIBRARIES} ${LIBAVUTIL_LIBRARIES})
list(APPEND DEPENDENCY_LIB ${LIBAVCODEC_LIBRARIES} ${LIBAVFORMAT_LIBRARIES} ${LIBAVRESAMPLE_LIBRARIES} ${LIBAVUTIL_LIBRARIES} ${LIBSWSCALE_LIBRARIES})
endif()
if(USE_PNG)

View File

@ -5,6 +5,9 @@
#include <libavutil/imgutils.h>
#include <libavutil/opt.h>
#include <libavresample/avresample.h>
#include <libswscale/swscale.h>
static void _ffmpegPostVideoFrame(struct GBAAVStream*, struct GBAVideoRenderer* renderer);
static void _ffmpegPostAudioFrame(struct GBAAVStream*, int32_t left, int32_t right);
@ -91,11 +94,19 @@ bool FFmpegEncoderSetVideo(struct FFmpegEncoder* encoder, const char* vcodec, un
enum AVPixelFormat format;
int priority;
} priorities[] = {
{ AV_PIX_FMT_RGB24, 0 },
{ AV_PIX_FMT_BGR0, 1 },
{ AV_PIX_FMT_YUV422P, 2 },
{ AV_PIX_FMT_YUV444P, 3 },
{ AV_PIX_FMT_YUV420P, 4 }
{ AV_PIX_FMT_RGB555, 0 },
{ AV_PIX_FMT_BGR555, 0 },
{ AV_PIX_FMT_RGB565, 1 },
{ AV_PIX_FMT_BGR565, 1 },
{ AV_PIX_FMT_RGB24, 2 },
{ AV_PIX_FMT_BGR24, 2 },
{ AV_PIX_FMT_BGR0, 3 },
{ AV_PIX_FMT_RGB0, 3 },
{ AV_PIX_FMT_0BGR, 3 },
{ AV_PIX_FMT_0RGB, 3 },
{ AV_PIX_FMT_YUV422P, 4 },
{ AV_PIX_FMT_YUV444P, 5 },
{ AV_PIX_FMT_YUV420P, 6 }
};
AVCodec* codec = avcodec_find_encoder_by_name(vcodec);
if (!codec) {
@ -202,6 +213,9 @@ bool FFmpegEncoderOpen(struct FFmpegEncoder* encoder, const char* outfile) {
encoder->videoFrame->width = encoder->video->width;
encoder->videoFrame->height = encoder->video->height;
encoder->videoFrame->pts = 0;
encoder->scaleContext = sws_getContext(VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS, AV_PIX_FMT_0BGR32,
VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS, encoder->video->pix_fmt,
0, 0, 0, 0);
av_image_alloc(encoder->videoFrame->data, encoder->videoFrame->linesize, encoder->video->width, encoder->video->height, encoder->video->pix_fmt, 32);
if (encoder->context->oformat->flags & AVFMT_GLOBALHEADER) {
@ -236,6 +250,8 @@ void FFmpegEncoderClose(struct FFmpegEncoder* encoder) {
avresample_close(encoder->resampleContext);
}
sws_freeContext(encoder->scaleContext);
avformat_free_context(encoder->context);
encoder->context = 0;
@ -294,9 +310,10 @@ void _ffmpegPostVideoFrame(struct GBAAVStream* stream, struct GBAVideoRenderer*
if (!encoder->context) {
return;
}
uint32_t* pixels;
uint8_t* pixels;
unsigned stride;
renderer->getPixels(renderer, &stride, (void**) &pixels);
stride *= 4;
AVPacket packet;
@ -307,26 +324,7 @@ void _ffmpegPostVideoFrame(struct GBAAVStream* stream, struct GBAVideoRenderer*
encoder->videoFrame->pts = av_rescale_q(encoder->currentVideoFrame, encoder->video->time_base, encoder->videoStream->time_base);
++encoder->currentVideoFrame;
unsigned x, y;
if (encoder->videoFrame->format == AV_PIX_FMT_BGR0) {
for (y = 0; y < VIDEO_VERTICAL_PIXELS; ++y) {
for (x = 0; x < VIDEO_HORIZONTAL_PIXELS; ++x) {
uint32_t pixel = pixels[stride * y + x];
encoder->videoFrame->data[0][y * encoder->videoFrame->linesize[0] + x * 4] = pixel >> 16;
encoder->videoFrame->data[0][y * encoder->videoFrame->linesize[0] + x * 4 + 1] = pixel >> 8;
encoder->videoFrame->data[0][y * encoder->videoFrame->linesize[0] + x * 4 + 2] = pixel;
}
}
} else if (encoder->videoFrame->format == AV_PIX_FMT_RGB24) {
for (y = 0; y < VIDEO_VERTICAL_PIXELS; ++y) {
for (x = 0; x < VIDEO_HORIZONTAL_PIXELS; ++x) {
uint32_t pixel = pixels[stride * y + x];
encoder->videoFrame->data[0][y * encoder->videoFrame->linesize[0] + x * 3] = pixel;
encoder->videoFrame->data[0][y * encoder->videoFrame->linesize[0] + x * 3 + 1] = pixel >> 8;
encoder->videoFrame->data[0][y * encoder->videoFrame->linesize[0] + x * 3 + 2] = pixel >> 16;
}
}
}
sws_scale(encoder->scaleContext, &pixels, &stride, 0, VIDEO_VERTICAL_PIXELS, encoder->videoFrame->data, encoder->videoFrame->linesize);
int gotData;
avcodec_encode_video2(encoder->video, &packet, encoder->videoFrame, &gotData);

View File

@ -5,7 +5,6 @@
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavresample/avresample.h>
struct FFmpegEncoder {
struct GBAAVStream d;
@ -30,13 +29,14 @@ struct FFmpegEncoder {
size_t currentAudioSample;
int64_t currentAudioFrame;
int64_t nextAudioPts;
AVAudioResampleContext* resampleContext;
struct AVAudioResampleContext* resampleContext;
AVStream* audioStream;
AVCodecContext* video;
enum AVPixelFormat pixFormat;
AVFrame* videoFrame;
int64_t currentVideoFrame;
struct SwsContext* scaleContext;
AVStream* videoStream;
};