mirror of
https://github.com/lvgl/lvgl.git
synced 2026-06-02 17:47:28 +08:00
feat(ffmpeg_player): add set_decoder (#9122)
Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
This commit is contained in:
@@ -70,6 +70,8 @@ This library can load videos and images. The LVGL file system
|
||||
will always be used when an image is loaded with :cpp:func:`lv_image_set_src`
|
||||
regardless of the value of :c:macro:`LV_FFMPEG_PLAYER_USE_LV_FS`.
|
||||
|
||||
The ffmpeg player uses software decoding by default. If you require a hardware decoder, you must manually specify it using ``lv_ffmpeg_player_set_decoder``, such as ``h264_v4l2m2m``.
|
||||
|
||||
See the examples below for how to correctly use this library.
|
||||
|
||||
|
||||
|
||||
+80
-35
@@ -84,7 +84,7 @@ static void decoder_close(lv_image_decoder_t * dec, lv_image_decoder_dsc_t * dsc
|
||||
static int ffmpeg_lvfs_read(void * ptr, uint8_t * buf, int buf_size);
|
||||
static int64_t ffmpeg_lvfs_seek(void * ptr, int64_t pos, int whence);
|
||||
static AVIOContext * ffmpeg_open_io_context(lv_fs_file_t * file);
|
||||
static struct ffmpeg_context_s * ffmpeg_open_file(const char * path, bool is_lv_fs_path);
|
||||
static struct ffmpeg_context_s * ffmpeg_open_file(const char * path, bool is_lv_fs_path, const char * decoder_name);
|
||||
static void ffmpeg_close(struct ffmpeg_context_s * ffmpeg_ctx);
|
||||
static void ffmpeg_close_src_ctx(struct ffmpeg_context_s * ffmpeg_ctx);
|
||||
static void ffmpeg_close_dst_ctx(struct ffmpeg_context_s * ffmpeg_ctx);
|
||||
@@ -148,7 +148,7 @@ void lv_ffmpeg_deinit(void)
|
||||
int lv_ffmpeg_get_frame_num(const char * path)
|
||||
{
|
||||
int ret = -1;
|
||||
struct ffmpeg_context_s * ffmpeg_ctx = ffmpeg_open_file(path, LV_FFMPEG_PLAYER_USE_LV_FS);
|
||||
struct ffmpeg_context_s * ffmpeg_ctx = ffmpeg_open_file(path, LV_FFMPEG_PLAYER_USE_LV_FS, NULL);
|
||||
|
||||
if(ffmpeg_ctx) {
|
||||
ret = ffmpeg_ctx->video_stream->nb_frames;
|
||||
@@ -179,7 +179,7 @@ lv_result_t lv_ffmpeg_player_set_src(lv_obj_t * obj, const char * path)
|
||||
|
||||
lv_timer_pause(player->timer);
|
||||
|
||||
player->ffmpeg_ctx = ffmpeg_open_file(path, LV_FFMPEG_PLAYER_USE_LV_FS);
|
||||
player->ffmpeg_ctx = ffmpeg_open_file(path, LV_FFMPEG_PLAYER_USE_LV_FS, player->decoder_name);
|
||||
|
||||
if(!player->ffmpeg_ctx) {
|
||||
goto failed;
|
||||
@@ -274,6 +274,16 @@ void lv_ffmpeg_player_set_auto_restart(lv_obj_t * obj, bool en)
|
||||
player->auto_restart = en;
|
||||
}
|
||||
|
||||
void lv_ffmpeg_player_set_decoder(lv_obj_t * obj, const char * name)
|
||||
{
|
||||
LV_ASSERT_OBJ(obj, MY_CLASS);
|
||||
lv_ffmpeg_player_t * player = (lv_ffmpeg_player_t *)obj;
|
||||
if(player->decoder_name) {
|
||||
lv_free((void *)player->decoder_name);
|
||||
}
|
||||
player->decoder_name = name ? lv_strdup(name) : NULL;
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
@@ -311,7 +321,7 @@ static lv_result_t decoder_open(lv_image_decoder_t * decoder, lv_image_decoder_d
|
||||
if(dsc->src_type == LV_IMAGE_SRC_FILE) {
|
||||
const char * path = dsc->src;
|
||||
|
||||
struct ffmpeg_context_s * ffmpeg_ctx = ffmpeg_open_file(path, true);
|
||||
struct ffmpeg_context_s * ffmpeg_ctx = ffmpeg_open_file(path, true, NULL);
|
||||
|
||||
if(ffmpeg_ctx == NULL) {
|
||||
return LV_RESULT_INVALID;
|
||||
@@ -538,15 +548,48 @@ static int ffmpeg_decode_packet(AVCodecContext * dec, const AVPacket * pkt,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ffmpeg_init_codec_context(AVCodecContext ** dec_ctx, const AVCodec * dec,
|
||||
enum AVMediaType type, AVStream * st)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
/* Allocate a codec context for the decoder */
|
||||
*dec_ctx = avcodec_alloc_context3(dec);
|
||||
if(*dec_ctx == NULL) {
|
||||
return AVERROR(ENOMEM);
|
||||
}
|
||||
|
||||
/* Copy codec parameters from input stream to output codec context */
|
||||
if((ret = avcodec_parameters_to_context(*dec_ctx, st->codecpar)) < 0) {
|
||||
LV_LOG_ERROR("Failed to allocate the %s codec context",
|
||||
av_get_media_type_string(type));
|
||||
goto free_dec_ctx;
|
||||
}
|
||||
|
||||
/* Init the decoders */
|
||||
if((ret = avcodec_open2(*dec_ctx, dec, NULL)) < 0) {
|
||||
LV_LOG_ERROR(
|
||||
"Failed to copy %s codec parameters to decoder context",
|
||||
av_get_media_type_string(type));
|
||||
goto free_dec_ctx;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
free_dec_ctx:
|
||||
avcodec_free_context(dec_ctx);
|
||||
*dec_ctx = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ffmpeg_open_codec_context(int * stream_idx,
|
||||
AVCodecContext ** dec_ctx, AVFormatContext * fmt_ctx,
|
||||
enum AVMediaType type)
|
||||
enum AVMediaType type, const char * decoder_name)
|
||||
{
|
||||
int ret;
|
||||
int stream_index;
|
||||
AVStream * st;
|
||||
const AVCodec * dec = NULL;
|
||||
AVDictionary * opts = NULL;
|
||||
|
||||
ret = av_find_best_stream(fmt_ctx, type, -1, -1, NULL, 0);
|
||||
if(ret < 0) {
|
||||
@@ -559,34 +602,29 @@ static int ffmpeg_open_codec_context(int * stream_idx,
|
||||
st = fmt_ctx->streams[stream_index];
|
||||
|
||||
/* find decoder for the stream */
|
||||
dec = avcodec_find_decoder(st->codecpar->codec_id);
|
||||
if(decoder_name) {
|
||||
dec = avcodec_find_decoder_by_name(decoder_name);
|
||||
if(dec) {
|
||||
ret = ffmpeg_init_codec_context(dec_ctx, dec, type, st);
|
||||
if(ret < 0) {
|
||||
dec = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(dec == NULL) {
|
||||
LV_LOG_ERROR("Failed to find %s codec",
|
||||
av_get_media_type_string(type));
|
||||
return AVERROR(EINVAL);
|
||||
}
|
||||
dec = avcodec_find_decoder(st->codecpar->codec_id);
|
||||
if(dec == NULL) {
|
||||
LV_LOG_ERROR("Failed to find %s codec",
|
||||
av_get_media_type_string(type));
|
||||
return AVERROR(EINVAL);
|
||||
}
|
||||
|
||||
/* Allocate a codec context for the decoder */
|
||||
*dec_ctx = avcodec_alloc_context3(dec);
|
||||
if(*dec_ctx == NULL) {
|
||||
LV_LOG_ERROR("Failed to allocate the %s codec context",
|
||||
av_get_media_type_string(type));
|
||||
return AVERROR(ENOMEM);
|
||||
}
|
||||
|
||||
/* Copy codec parameters from input stream to output codec context */
|
||||
if((ret = avcodec_parameters_to_context(*dec_ctx, st->codecpar)) < 0) {
|
||||
LV_LOG_ERROR(
|
||||
"Failed to copy %s codec parameters to decoder context",
|
||||
av_get_media_type_string(type));
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Init the decoders */
|
||||
if((ret = avcodec_open2(*dec_ctx, dec, &opts)) < 0) {
|
||||
LV_LOG_ERROR("Failed to open %s codec",
|
||||
av_get_media_type_string(type));
|
||||
return ret;
|
||||
ret = ffmpeg_init_codec_context(dec_ctx, dec, type, st);
|
||||
if(ret < 0) {
|
||||
LV_LOG_ERROR("Failed to initialize %s codec context",
|
||||
av_get_media_type_string(type));
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
*stream_idx = stream_index;
|
||||
@@ -632,7 +670,7 @@ static int ffmpeg_get_image_header(lv_image_decoder_dsc_t * dsc,
|
||||
}
|
||||
|
||||
if(ffmpeg_open_codec_context(&video_stream_idx, &video_dec_ctx,
|
||||
fmt_ctx, AVMEDIA_TYPE_VIDEO)
|
||||
fmt_ctx, AVMEDIA_TYPE_VIDEO, NULL)
|
||||
>= 0) {
|
||||
bool has_alpha = ffmpeg_pix_fmt_has_alpha(video_dec_ctx->pix_fmt);
|
||||
|
||||
@@ -748,7 +786,7 @@ static AVIOContext * ffmpeg_open_io_context(lv_fs_file_t * file)
|
||||
return pIOCtx;
|
||||
}
|
||||
|
||||
static struct ffmpeg_context_s * ffmpeg_open_file(const char * path, bool is_lv_fs_path)
|
||||
static struct ffmpeg_context_s * ffmpeg_open_file(const char * path, bool is_lv_fs_path, const char * decoder_name)
|
||||
{
|
||||
if(path == NULL || lv_strlen(path) == 0) {
|
||||
LV_LOG_ERROR("file path is empty");
|
||||
@@ -803,7 +841,7 @@ static struct ffmpeg_context_s * ffmpeg_open_file(const char * path, bool is_lv_
|
||||
if(ffmpeg_open_codec_context(
|
||||
&(ffmpeg_ctx->video_stream_idx),
|
||||
&(ffmpeg_ctx->video_dec_ctx),
|
||||
ffmpeg_ctx->fmt_ctx, AVMEDIA_TYPE_VIDEO)
|
||||
ffmpeg_ctx->fmt_ctx, AVMEDIA_TYPE_VIDEO, decoder_name)
|
||||
>= 0) {
|
||||
ffmpeg_ctx->video_stream = ffmpeg_ctx->fmt_ctx->streams[ffmpeg_ctx->video_stream_idx];
|
||||
|
||||
@@ -963,6 +1001,8 @@ static void lv_ffmpeg_player_constructor(const lv_obj_class_t * class_p,
|
||||
FRAME_DEF_REFR_PERIOD, obj);
|
||||
lv_timer_pause(player->timer);
|
||||
|
||||
player->decoder_name = NULL;
|
||||
|
||||
LV_TRACE_OBJ_CREATE("finished");
|
||||
}
|
||||
|
||||
@@ -985,6 +1025,11 @@ static void lv_ffmpeg_player_destructor(const lv_obj_class_t * class_p,
|
||||
ffmpeg_close(player->ffmpeg_ctx);
|
||||
player->ffmpeg_ctx = NULL;
|
||||
|
||||
if(player->decoder_name) {
|
||||
lv_free((void *)player->decoder_name);
|
||||
player->decoder_name = NULL;
|
||||
}
|
||||
|
||||
LV_TRACE_OBJ_CREATE("finished");
|
||||
}
|
||||
|
||||
|
||||
@@ -85,6 +85,12 @@ void lv_ffmpeg_player_set_cmd(lv_obj_t * obj, lv_ffmpeg_player_cmd_t cmd);
|
||||
*/
|
||||
void lv_ffmpeg_player_set_auto_restart(lv_obj_t * obj, bool en);
|
||||
|
||||
/**
|
||||
* Set the video decoder
|
||||
* @param obj pointer to a ffmpeg_player object
|
||||
* @param decoder_name decoder name
|
||||
*/
|
||||
void lv_ffmpeg_player_set_decoder(lv_obj_t * obj, const char * decoder_name);
|
||||
/*=====================
|
||||
* Other functions
|
||||
*====================*/
|
||||
|
||||
@@ -32,6 +32,7 @@ struct _lv_ffmpeg_player_t {
|
||||
lv_image_dsc_t imgdsc;
|
||||
bool auto_restart;
|
||||
struct ffmpeg_context_s * ffmpeg_ctx;
|
||||
const char * decoder_name;
|
||||
};
|
||||
|
||||
/**********************
|
||||
|
||||
Reference in New Issue
Block a user