mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-01 01:07:51 -04:00
ffmpeg: support videos with alpha; add ffmpeg-prefer-libvpx prc var
ffmpeg-prefer-libvpx forces ffmpeg to use the libvpx decoder for VP8/VP9 files, allowing the playback of WebM files with an alpha channel.
This commit is contained in:
parent
34068dc0c1
commit
b6cb9b0045
@ -76,6 +76,14 @@ ConfigVariableInt ffmpeg_read_buffer_size
|
||||
"This is important for performance. A typical size is that of a "
|
||||
"cache page, e.g. 4kb."));
|
||||
|
||||
ConfigVariableBool ffmpeg_prefer_libvpx
|
||||
("ffmpeg-prefer-libvpx", false,
|
||||
PRC_DESC("If this is true, Panda will overrule ffmpeg's best judgment on "
|
||||
"which decoder to use for decoding VP8 and VP9 files, and try to "
|
||||
"choose libvpx. This is useful when you want to play WebM videos "
|
||||
"with an alpha channel, which aren't supported by ffmpeg's own "
|
||||
"VP8/VP9 decoders."));
|
||||
|
||||
/**
|
||||
* Initializes the library. This must be called at least once before any of
|
||||
* the functions or classes in this library can be used. Normally it will be
|
||||
|
@ -31,6 +31,7 @@ extern ConfigVariableBool ffmpeg_support_seek;
|
||||
extern ConfigVariableBool ffmpeg_global_lock;
|
||||
extern ConfigVariableEnum<ThreadPriority> ffmpeg_thread_priority;
|
||||
extern ConfigVariableInt ffmpeg_read_buffer_size;
|
||||
extern ConfigVariableBool ffmpeg_prefer_libvpx;
|
||||
|
||||
extern EXPCL_FFMPEG void init_libffmpeg();
|
||||
|
||||
|
@ -22,6 +22,7 @@
|
||||
extern "C" {
|
||||
#include "libavcodec/avcodec.h"
|
||||
#include "libavformat/avformat.h"
|
||||
#include "libavutil/pixdesc.h"
|
||||
#ifdef HAVE_SWSCALE
|
||||
#include "libswscale/swscale.h"
|
||||
#endif
|
||||
@ -35,11 +36,16 @@ PStatCollector FfmpegVideoCursor::_fetch_buffer_pcollector("*:FFMPEG Video Decod
|
||||
PStatCollector FfmpegVideoCursor::_seek_pcollector("*:FFMPEG Video Decoding:Seek");
|
||||
PStatCollector FfmpegVideoCursor::_export_frame_pcollector("*:FFMPEG Convert Video to BGR");
|
||||
|
||||
|
||||
#if LIBAVFORMAT_VERSION_MAJOR < 53
|
||||
#define AVMEDIA_TYPE_VIDEO CODEC_TYPE_VIDEO
|
||||
#endif
|
||||
|
||||
#if LIBAVUTIL_VERSION_INT < AV_VERSION_INT(51, 74, 100)
|
||||
#define AV_PIX_FMT_NONE PIX_FMT_NONE
|
||||
#define AV_PIX_FMT_BGR24 PIX_FMT_BGR24
|
||||
#define AV_PIX_FMT_BGRA PIX_FMT_BGRA
|
||||
#endif
|
||||
|
||||
/**
|
||||
* This constructor is only used when reading from a bam file.
|
||||
*/
|
||||
@ -55,6 +61,7 @@ FfmpegVideoCursor() :
|
||||
_format_ctx(NULL),
|
||||
_video_ctx(NULL),
|
||||
_convert_ctx(NULL),
|
||||
_pixel_format(AV_PIX_FMT_NONE),
|
||||
_video_index(-1),
|
||||
_frame(NULL),
|
||||
_frame_out(NULL),
|
||||
@ -80,17 +87,6 @@ init_from(FfmpegVideo *source) {
|
||||
|
||||
ReMutexHolder av_holder(_av_lock);
|
||||
|
||||
#ifdef HAVE_SWSCALE
|
||||
nassertv(_convert_ctx == NULL);
|
||||
_convert_ctx = sws_getContext(_size_x, _size_y, _video_ctx->pix_fmt,
|
||||
#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(51, 74, 100)
|
||||
_size_x, _size_y, AV_PIX_FMT_BGR24,
|
||||
#else
|
||||
_size_x, _size_y, PIX_FMT_BGR24,
|
||||
#endif
|
||||
SWS_BILINEAR | SWS_PRINT_INFO, NULL, NULL, NULL);
|
||||
#endif // HAVE_SWSCALE
|
||||
|
||||
#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(54, 59, 100)
|
||||
_frame = av_frame_alloc();
|
||||
_frame_out = av_frame_alloc();
|
||||
@ -115,6 +111,25 @@ init_from(FfmpegVideo *source) {
|
||||
_eof_known = false;
|
||||
_eof_frame = 0;
|
||||
|
||||
// Check if we got an alpha format. Please note that some video codecs
|
||||
// (eg. libvpx) change the pix_fmt after decoding the first frame, which is
|
||||
// why we didn't do this earlier.
|
||||
const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(_video_ctx->pix_fmt);
|
||||
if (desc && (desc->flags & AV_PIX_FMT_FLAG_ALPHA) != 0) {
|
||||
_num_components = 4;
|
||||
_pixel_format = AV_PIX_FMT_BGRA;
|
||||
} else {
|
||||
_num_components = 3;
|
||||
_pixel_format = AV_PIX_FMT_BGR24;
|
||||
}
|
||||
|
||||
#ifdef HAVE_SWSCALE
|
||||
nassertv(_convert_ctx == NULL);
|
||||
_convert_ctx = sws_getContext(_size_x, _size_y, _video_ctx->pix_fmt,
|
||||
_size_x, _size_y, _pixel_format,
|
||||
SWS_BILINEAR | SWS_PRINT_INFO, NULL, NULL, NULL);
|
||||
#endif // HAVE_SWSCALE
|
||||
|
||||
#ifdef HAVE_THREADS
|
||||
set_max_readahead_frames(ffmpeg_max_readahead_frames);
|
||||
#endif // HAVE_THREADS
|
||||
@ -495,7 +510,17 @@ open_stream() {
|
||||
return false;
|
||||
}
|
||||
|
||||
AVCodec *pVideoCodec = avcodec_find_decoder(_video_ctx->codec_id);
|
||||
AVCodec *pVideoCodec = NULL;
|
||||
if (ffmpeg_prefer_libvpx) {
|
||||
if (_video_ctx->codec_id == AV_CODEC_ID_VP9) {
|
||||
pVideoCodec = avcodec_find_decoder_by_name("libvpx-vp9");
|
||||
} else if (_video_ctx->codec_id == AV_CODEC_ID_VP8) {
|
||||
pVideoCodec = avcodec_find_decoder_by_name("libvpx");
|
||||
}
|
||||
}
|
||||
if (pVideoCodec == NULL) {
|
||||
pVideoCodec = avcodec_find_decoder(_video_ctx->codec_id);
|
||||
}
|
||||
if (pVideoCodec == NULL) {
|
||||
ffmpeg_cat.info()
|
||||
<< "Couldn't find codec\n";
|
||||
@ -515,7 +540,7 @@ open_stream() {
|
||||
|
||||
_size_x = _video_ctx->width;
|
||||
_size_y = _video_ctx->height;
|
||||
_num_components = 3; // Don't know how to implement RGBA movies yet.
|
||||
_num_components = 3;
|
||||
_length = (double)_format_ctx->duration / (double)AV_TIME_BASE;
|
||||
_can_seek = true;
|
||||
_can_seek_fast = true;
|
||||
@ -1075,8 +1100,8 @@ export_frame(FfmpegBuffer *buffer) {
|
||||
return;
|
||||
}
|
||||
|
||||
_frame_out->data[0] = buffer->_block + ((_size_y - 1) * _size_x * 3);
|
||||
_frame_out->linesize[0] = _size_x * -3;
|
||||
_frame_out->data[0] = buffer->_block + ((_size_y - 1) * _size_x * _num_components);
|
||||
_frame_out->linesize[0] = _size_x * -_num_components;
|
||||
buffer->_begin_frame = _begin_frame;
|
||||
buffer->_end_frame = _end_frame;
|
||||
|
||||
@ -1086,7 +1111,7 @@ export_frame(FfmpegBuffer *buffer) {
|
||||
nassertv(_convert_ctx != NULL && _frame != NULL && _frame_out != NULL);
|
||||
sws_scale(_convert_ctx, _frame->data, _frame->linesize, 0, _size_y, _frame_out->data, _frame_out->linesize);
|
||||
#else
|
||||
img_convert((AVPicture *)_frame_out, PIX_FMT_BGR24,
|
||||
img_convert((AVPicture *)_frame_out, _pixel_format,
|
||||
(AVPicture *)_frame, _video_ctx->pix_fmt, _size_x, _size_y);
|
||||
#endif
|
||||
} else {
|
||||
@ -1094,7 +1119,7 @@ export_frame(FfmpegBuffer *buffer) {
|
||||
nassertv(_convert_ctx != NULL && _frame != NULL && _frame_out != NULL);
|
||||
sws_scale(_convert_ctx, _frame->data, _frame->linesize, 0, _size_y, _frame_out->data, _frame_out->linesize);
|
||||
#else
|
||||
img_convert((AVPicture *)_frame_out, PIX_FMT_BGR24,
|
||||
img_convert((AVPicture *)_frame_out, _pixel_format,
|
||||
(AVPicture *)_frame, _video_ctx->pix_fmt, _size_x, _size_y);
|
||||
#endif
|
||||
}
|
||||
|
@ -104,6 +104,7 @@ private:
|
||||
int _max_readahead_frames;
|
||||
ThreadPriority _thread_priority;
|
||||
PT(GenericThread) _thread;
|
||||
AVPixelFormat _pixel_format;
|
||||
|
||||
// This global Mutex protects calls to avcodec_opencloseetc.
|
||||
static ReMutex _av_lock;
|
||||
|
Loading…
x
Reference in New Issue
Block a user