mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-03 10:22:45 -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 "
|
"This is important for performance. A typical size is that of a "
|
||||||
"cache page, e.g. 4kb."));
|
"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
|
* 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
|
* 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 ConfigVariableBool ffmpeg_global_lock;
|
||||||
extern ConfigVariableEnum<ThreadPriority> ffmpeg_thread_priority;
|
extern ConfigVariableEnum<ThreadPriority> ffmpeg_thread_priority;
|
||||||
extern ConfigVariableInt ffmpeg_read_buffer_size;
|
extern ConfigVariableInt ffmpeg_read_buffer_size;
|
||||||
|
extern ConfigVariableBool ffmpeg_prefer_libvpx;
|
||||||
|
|
||||||
extern EXPCL_FFMPEG void init_libffmpeg();
|
extern EXPCL_FFMPEG void init_libffmpeg();
|
||||||
|
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#include "libavcodec/avcodec.h"
|
#include "libavcodec/avcodec.h"
|
||||||
#include "libavformat/avformat.h"
|
#include "libavformat/avformat.h"
|
||||||
|
#include "libavutil/pixdesc.h"
|
||||||
#ifdef HAVE_SWSCALE
|
#ifdef HAVE_SWSCALE
|
||||||
#include "libswscale/swscale.h"
|
#include "libswscale/swscale.h"
|
||||||
#endif
|
#endif
|
||||||
@ -35,11 +36,16 @@ PStatCollector FfmpegVideoCursor::_fetch_buffer_pcollector("*:FFMPEG Video Decod
|
|||||||
PStatCollector FfmpegVideoCursor::_seek_pcollector("*:FFMPEG Video Decoding:Seek");
|
PStatCollector FfmpegVideoCursor::_seek_pcollector("*:FFMPEG Video Decoding:Seek");
|
||||||
PStatCollector FfmpegVideoCursor::_export_frame_pcollector("*:FFMPEG Convert Video to BGR");
|
PStatCollector FfmpegVideoCursor::_export_frame_pcollector("*:FFMPEG Convert Video to BGR");
|
||||||
|
|
||||||
|
|
||||||
#if LIBAVFORMAT_VERSION_MAJOR < 53
|
#if LIBAVFORMAT_VERSION_MAJOR < 53
|
||||||
#define AVMEDIA_TYPE_VIDEO CODEC_TYPE_VIDEO
|
#define AVMEDIA_TYPE_VIDEO CODEC_TYPE_VIDEO
|
||||||
#endif
|
#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.
|
* This constructor is only used when reading from a bam file.
|
||||||
*/
|
*/
|
||||||
@ -55,6 +61,7 @@ FfmpegVideoCursor() :
|
|||||||
_format_ctx(NULL),
|
_format_ctx(NULL),
|
||||||
_video_ctx(NULL),
|
_video_ctx(NULL),
|
||||||
_convert_ctx(NULL),
|
_convert_ctx(NULL),
|
||||||
|
_pixel_format(AV_PIX_FMT_NONE),
|
||||||
_video_index(-1),
|
_video_index(-1),
|
||||||
_frame(NULL),
|
_frame(NULL),
|
||||||
_frame_out(NULL),
|
_frame_out(NULL),
|
||||||
@ -80,17 +87,6 @@ init_from(FfmpegVideo *source) {
|
|||||||
|
|
||||||
ReMutexHolder av_holder(_av_lock);
|
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)
|
#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(54, 59, 100)
|
||||||
_frame = av_frame_alloc();
|
_frame = av_frame_alloc();
|
||||||
_frame_out = av_frame_alloc();
|
_frame_out = av_frame_alloc();
|
||||||
@ -115,6 +111,25 @@ init_from(FfmpegVideo *source) {
|
|||||||
_eof_known = false;
|
_eof_known = false;
|
||||||
_eof_frame = 0;
|
_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
|
#ifdef HAVE_THREADS
|
||||||
set_max_readahead_frames(ffmpeg_max_readahead_frames);
|
set_max_readahead_frames(ffmpeg_max_readahead_frames);
|
||||||
#endif // HAVE_THREADS
|
#endif // HAVE_THREADS
|
||||||
@ -495,7 +510,17 @@ open_stream() {
|
|||||||
return false;
|
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) {
|
if (pVideoCodec == NULL) {
|
||||||
ffmpeg_cat.info()
|
ffmpeg_cat.info()
|
||||||
<< "Couldn't find codec\n";
|
<< "Couldn't find codec\n";
|
||||||
@ -515,7 +540,7 @@ open_stream() {
|
|||||||
|
|
||||||
_size_x = _video_ctx->width;
|
_size_x = _video_ctx->width;
|
||||||
_size_y = _video_ctx->height;
|
_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;
|
_length = (double)_format_ctx->duration / (double)AV_TIME_BASE;
|
||||||
_can_seek = true;
|
_can_seek = true;
|
||||||
_can_seek_fast = true;
|
_can_seek_fast = true;
|
||||||
@ -1075,8 +1100,8 @@ export_frame(FfmpegBuffer *buffer) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_frame_out->data[0] = buffer->_block + ((_size_y - 1) * _size_x * 3);
|
_frame_out->data[0] = buffer->_block + ((_size_y - 1) * _size_x * _num_components);
|
||||||
_frame_out->linesize[0] = _size_x * -3;
|
_frame_out->linesize[0] = _size_x * -_num_components;
|
||||||
buffer->_begin_frame = _begin_frame;
|
buffer->_begin_frame = _begin_frame;
|
||||||
buffer->_end_frame = _end_frame;
|
buffer->_end_frame = _end_frame;
|
||||||
|
|
||||||
@ -1086,7 +1111,7 @@ export_frame(FfmpegBuffer *buffer) {
|
|||||||
nassertv(_convert_ctx != NULL && _frame != NULL && _frame_out != NULL);
|
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);
|
sws_scale(_convert_ctx, _frame->data, _frame->linesize, 0, _size_y, _frame_out->data, _frame_out->linesize);
|
||||||
#else
|
#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);
|
(AVPicture *)_frame, _video_ctx->pix_fmt, _size_x, _size_y);
|
||||||
#endif
|
#endif
|
||||||
} else {
|
} else {
|
||||||
@ -1094,7 +1119,7 @@ export_frame(FfmpegBuffer *buffer) {
|
|||||||
nassertv(_convert_ctx != NULL && _frame != NULL && _frame_out != NULL);
|
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);
|
sws_scale(_convert_ctx, _frame->data, _frame->linesize, 0, _size_y, _frame_out->data, _frame_out->linesize);
|
||||||
#else
|
#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);
|
(AVPicture *)_frame, _video_ctx->pix_fmt, _size_x, _size_y);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -104,6 +104,7 @@ private:
|
|||||||
int _max_readahead_frames;
|
int _max_readahead_frames;
|
||||||
ThreadPriority _thread_priority;
|
ThreadPriority _thread_priority;
|
||||||
PT(GenericThread) _thread;
|
PT(GenericThread) _thread;
|
||||||
|
AVPixelFormat _pixel_format;
|
||||||
|
|
||||||
// This global Mutex protects calls to avcodec_opencloseetc.
|
// This global Mutex protects calls to avcodec_opencloseetc.
|
||||||
static ReMutex _av_lock;
|
static ReMutex _av_lock;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user