acid-drop- Hacking the planet from a LilyGo T-Deck using custom firmware |
git clone git://git.acid.vegas/acid-drop.git |
Log | Files | Refs | Archive | README | LICENSE |
lv_ffmpeg.c (25804B)
1 /** 2 * @file lv_ffmpeg.c 3 * 4 */ 5 6 /********************* 7 * INCLUDES 8 *********************/ 9 #include "lv_ffmpeg.h" 10 #if LV_USE_FFMPEG != 0 11 12 #include <libavcodec/avcodec.h> 13 #include <libavformat/avformat.h> 14 #include <libavutil/imgutils.h> 15 #include <libavutil/samplefmt.h> 16 #include <libavutil/timestamp.h> 17 #include <libswscale/swscale.h> 18 19 /********************* 20 * DEFINES 21 *********************/ 22 #if LV_COLOR_DEPTH == 1 || LV_COLOR_DEPTH == 8 23 #define AV_PIX_FMT_TRUE_COLOR AV_PIX_FMT_RGB8 24 #elif LV_COLOR_DEPTH == 16 25 #if LV_COLOR_16_SWAP == 0 26 #define AV_PIX_FMT_TRUE_COLOR AV_PIX_FMT_RGB565LE 27 #else 28 #define AV_PIX_FMT_TRUE_COLOR AV_PIX_FMT_RGB565BE 29 #endif 30 #elif LV_COLOR_DEPTH == 32 31 #define AV_PIX_FMT_TRUE_COLOR AV_PIX_FMT_BGR0 32 #else 33 #error Unsupported LV_COLOR_DEPTH 34 #endif 35 36 #define MY_CLASS &lv_ffmpeg_player_class 37 38 #define FRAME_DEF_REFR_PERIOD 33 /*[ms]*/ 39 40 /********************** 41 * TYPEDEFS 42 **********************/ 43 struct ffmpeg_context_s { 44 AVFormatContext * fmt_ctx; 45 AVCodecContext * video_dec_ctx; 46 AVStream * video_stream; 47 uint8_t * video_src_data[4]; 48 uint8_t * video_dst_data[4]; 49 struct SwsContext * sws_ctx; 50 AVFrame * frame; 51 AVPacket pkt; 52 int video_stream_idx; 53 int video_src_linesize[4]; 54 int video_dst_linesize[4]; 55 enum AVPixelFormat video_dst_pix_fmt; 56 bool has_alpha; 57 }; 58 59 #pragma pack(1) 60 61 struct lv_img_pixel_color_s { 62 lv_color_t c; 63 uint8_t alpha; 64 }; 65 66 #pragma pack() 67 68 /********************** 69 * STATIC PROTOTYPES 70 **********************/ 71 72 static lv_res_t decoder_info(lv_img_decoder_t * decoder, const void * src, lv_img_header_t * header); 73 static lv_res_t decoder_open(lv_img_decoder_t * dec, lv_img_decoder_dsc_t * dsc); 74 static void decoder_close(lv_img_decoder_t * dec, lv_img_decoder_dsc_t * dsc); 75 76 static struct ffmpeg_context_s * ffmpeg_open_file(const char * path); 77 static void ffmpeg_close(struct ffmpeg_context_s * ffmpeg_ctx); 78 static void ffmpeg_close_src_ctx(struct ffmpeg_context_s * ffmpeg_ctx); 79 static void ffmpeg_close_dst_ctx(struct ffmpeg_context_s * ffmpeg_ctx); 80 static int ffmpeg_image_allocate(struct ffmpeg_context_s * ffmpeg_ctx); 81 static int ffmpeg_get_img_header(const char * path, lv_img_header_t * header); 82 static int ffmpeg_get_frame_refr_period(struct ffmpeg_context_s * ffmpeg_ctx); 83 static uint8_t * ffmpeg_get_img_data(struct ffmpeg_context_s * ffmpeg_ctx); 84 static int ffmpeg_update_next_frame(struct ffmpeg_context_s * ffmpeg_ctx); 85 static int ffmpeg_output_video_frame(struct ffmpeg_context_s * ffmpeg_ctx); 86 static bool ffmpeg_pix_fmt_has_alpha(enum AVPixelFormat pix_fmt); 87 static bool ffmpeg_pix_fmt_is_yuv(enum AVPixelFormat pix_fmt); 88 89 static void lv_ffmpeg_player_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj); 90 static void lv_ffmpeg_player_destructor(const lv_obj_class_t * class_p, lv_obj_t * obj); 91 92 #if LV_COLOR_DEPTH != 32 93 static void convert_color_depth(uint8_t * img, uint32_t px_cnt); 94 #endif 95 96 /********************** 97 * STATIC VARIABLES 98 **********************/ 99 const lv_obj_class_t lv_ffmpeg_player_class = { 100 .constructor_cb = lv_ffmpeg_player_constructor, 101 .destructor_cb = lv_ffmpeg_player_destructor, 102 .instance_size = sizeof(lv_ffmpeg_player_t), 103 .base_class = &lv_img_class 104 }; 105 106 /********************** 107 * MACROS 108 **********************/ 109 110 /********************** 111 * GLOBAL FUNCTIONS 112 **********************/ 113 114 void lv_ffmpeg_init(void) 115 { 116 lv_img_decoder_t * dec = lv_img_decoder_create(); 117 lv_img_decoder_set_info_cb(dec, decoder_info); 118 lv_img_decoder_set_open_cb(dec, decoder_open); 119 lv_img_decoder_set_close_cb(dec, decoder_close); 120 121 #if LV_FFMPEG_AV_DUMP_FORMAT == 0 122 av_log_set_level(AV_LOG_QUIET); 123 #endif 124 } 125 126 int lv_ffmpeg_get_frame_num(const char * path) 127 { 128 int ret = -1; 129 struct ffmpeg_context_s * ffmpeg_ctx = ffmpeg_open_file(path); 130 131 if(ffmpeg_ctx) { 132 ret = ffmpeg_ctx->video_stream->nb_frames; 133 ffmpeg_close(ffmpeg_ctx); 134 } 135 136 return ret; 137 } 138 139 lv_obj_t * lv_ffmpeg_player_create(lv_obj_t * parent) 140 { 141 lv_obj_t * obj = lv_obj_class_create_obj(MY_CLASS, parent); 142 lv_obj_class_init_obj(obj); 143 return obj; 144 } 145 146 lv_res_t lv_ffmpeg_player_set_src(lv_obj_t * obj, const char * path) 147 { 148 LV_ASSERT_OBJ(obj, MY_CLASS); 149 lv_res_t res = LV_RES_INV; 150 151 lv_ffmpeg_player_t * player = (lv_ffmpeg_player_t *)obj; 152 153 if(player->ffmpeg_ctx) { 154 ffmpeg_close(player->ffmpeg_ctx); 155 player->ffmpeg_ctx = NULL; 156 } 157 158 lv_timer_pause(player->timer); 159 160 player->ffmpeg_ctx = ffmpeg_open_file(path); 161 162 if(!player->ffmpeg_ctx) { 163 LV_LOG_ERROR("ffmpeg file open failed: %s", path); 164 goto failed; 165 } 166 167 if(ffmpeg_image_allocate(player->ffmpeg_ctx) < 0) { 168 LV_LOG_ERROR("ffmpeg image allocate failed"); 169 ffmpeg_close(player->ffmpeg_ctx); 170 goto failed; 171 } 172 173 bool has_alpha = player->ffmpeg_ctx->has_alpha; 174 int width = player->ffmpeg_ctx->video_dec_ctx->width; 175 int height = player->ffmpeg_ctx->video_dec_ctx->height; 176 uint32_t data_size = 0; 177 178 if(has_alpha) { 179 data_size = width * height * LV_IMG_PX_SIZE_ALPHA_BYTE; 180 } 181 else { 182 data_size = width * height * LV_COLOR_SIZE / 8; 183 } 184 185 player->imgdsc.header.always_zero = 0; 186 player->imgdsc.header.w = width; 187 player->imgdsc.header.h = height; 188 player->imgdsc.data_size = data_size; 189 player->imgdsc.header.cf = has_alpha ? LV_IMG_CF_TRUE_COLOR_ALPHA : LV_IMG_CF_TRUE_COLOR; 190 player->imgdsc.data = ffmpeg_get_img_data(player->ffmpeg_ctx); 191 192 lv_img_set_src(&player->img.obj, &(player->imgdsc)); 193 194 int period = ffmpeg_get_frame_refr_period(player->ffmpeg_ctx); 195 196 if(period > 0) { 197 LV_LOG_INFO("frame refresh period = %d ms, rate = %d fps", 198 period, 1000 / period); 199 lv_timer_set_period(player->timer, period); 200 } 201 else { 202 LV_LOG_WARN("unable to get frame refresh period"); 203 } 204 205 res = LV_RES_OK; 206 207 failed: 208 return res; 209 } 210 211 void lv_ffmpeg_player_set_cmd(lv_obj_t * obj, lv_ffmpeg_player_cmd_t cmd) 212 { 213 LV_ASSERT_OBJ(obj, MY_CLASS); 214 lv_ffmpeg_player_t * player = (lv_ffmpeg_player_t *)obj; 215 216 if(!player->ffmpeg_ctx) { 217 LV_LOG_ERROR("ffmpeg_ctx is NULL"); 218 return; 219 } 220 221 lv_timer_t * timer = player->timer; 222 223 switch(cmd) { 224 case LV_FFMPEG_PLAYER_CMD_START: 225 av_seek_frame(player->ffmpeg_ctx->fmt_ctx, 226 0, 0, AVSEEK_FLAG_BACKWARD); 227 lv_timer_resume(timer); 228 LV_LOG_INFO("ffmpeg player start"); 229 break; 230 case LV_FFMPEG_PLAYER_CMD_STOP: 231 av_seek_frame(player->ffmpeg_ctx->fmt_ctx, 232 0, 0, AVSEEK_FLAG_BACKWARD); 233 lv_timer_pause(timer); 234 LV_LOG_INFO("ffmpeg player stop"); 235 break; 236 case LV_FFMPEG_PLAYER_CMD_PAUSE: 237 lv_timer_pause(timer); 238 LV_LOG_INFO("ffmpeg player pause"); 239 break; 240 case LV_FFMPEG_PLAYER_CMD_RESUME: 241 lv_timer_resume(timer); 242 LV_LOG_INFO("ffmpeg player resume"); 243 break; 244 default: 245 LV_LOG_ERROR("Error cmd: %d", cmd); 246 break; 247 } 248 } 249 250 void lv_ffmpeg_player_set_auto_restart(lv_obj_t * obj, bool en) 251 { 252 LV_ASSERT_OBJ(obj, MY_CLASS); 253 lv_ffmpeg_player_t * player = (lv_ffmpeg_player_t *)obj; 254 player->auto_restart = en; 255 } 256 257 /********************** 258 * STATIC FUNCTIONS 259 **********************/ 260 261 static lv_res_t decoder_info(lv_img_decoder_t * decoder, const void * src, lv_img_header_t * header) 262 { 263 /* Get the source type */ 264 lv_img_src_t src_type = lv_img_src_get_type(src); 265 266 if(src_type == LV_IMG_SRC_FILE) { 267 const char * fn = src; 268 269 if(ffmpeg_get_img_header(fn, header) < 0) { 270 LV_LOG_ERROR("ffmpeg can't get image header"); 271 return LV_RES_INV; 272 } 273 274 return LV_RES_OK; 275 } 276 277 /* If didn't succeeded earlier then it's an error */ 278 return LV_RES_INV; 279 } 280 281 static lv_res_t decoder_open(lv_img_decoder_t * decoder, lv_img_decoder_dsc_t * dsc) 282 { 283 if(dsc->src_type == LV_IMG_SRC_FILE) { 284 const char * path = dsc->src; 285 286 struct ffmpeg_context_s * ffmpeg_ctx = ffmpeg_open_file(path); 287 288 if(ffmpeg_ctx == NULL) { 289 return LV_RES_INV; 290 } 291 292 if(ffmpeg_image_allocate(ffmpeg_ctx) < 0) { 293 LV_LOG_ERROR("ffmpeg image allocate failed"); 294 ffmpeg_close(ffmpeg_ctx); 295 return LV_RES_INV; 296 } 297 298 if(ffmpeg_update_next_frame(ffmpeg_ctx) < 0) { 299 ffmpeg_close(ffmpeg_ctx); 300 LV_LOG_ERROR("ffmpeg update frame failed"); 301 return LV_RES_INV; 302 } 303 304 ffmpeg_close_src_ctx(ffmpeg_ctx); 305 uint8_t * img_data = ffmpeg_get_img_data(ffmpeg_ctx); 306 307 #if LV_COLOR_DEPTH != 32 308 if(ffmpeg_ctx->has_alpha) { 309 convert_color_depth(img_data, dsc->header.w * dsc->header.h); 310 } 311 #endif 312 313 dsc->user_data = ffmpeg_ctx; 314 dsc->img_data = img_data; 315 316 /* The image is fully decoded. Return with its pointer */ 317 return LV_RES_OK; 318 } 319 320 /* If not returned earlier then it failed */ 321 return LV_RES_INV; 322 } 323 324 static void decoder_close(lv_img_decoder_t * decoder, lv_img_decoder_dsc_t * dsc) 325 { 326 struct ffmpeg_context_s * ffmpeg_ctx = dsc->user_data; 327 ffmpeg_close(ffmpeg_ctx); 328 } 329 330 #if LV_COLOR_DEPTH != 32 331 332 static void convert_color_depth(uint8_t * img, uint32_t px_cnt) 333 { 334 lv_color32_t * img_src_p = (lv_color32_t *)img; 335 struct lv_img_pixel_color_s * img_dst_p = (struct lv_img_pixel_color_s *)img; 336 337 for(uint32_t i = 0; i < px_cnt; i++) { 338 lv_color32_t temp = *img_src_p; 339 img_dst_p->c = lv_color_hex(temp.full); 340 img_dst_p->alpha = temp.ch.alpha; 341 342 img_src_p++; 343 img_dst_p++; 344 } 345 } 346 347 #endif 348 349 static uint8_t * ffmpeg_get_img_data(struct ffmpeg_context_s * ffmpeg_ctx) 350 { 351 uint8_t * img_data = ffmpeg_ctx->video_dst_data[0]; 352 353 if(img_data == NULL) { 354 LV_LOG_ERROR("ffmpeg video dst data is NULL"); 355 } 356 357 return img_data; 358 } 359 360 static bool ffmpeg_pix_fmt_has_alpha(enum AVPixelFormat pix_fmt) 361 { 362 const AVPixFmtDescriptor * desc = av_pix_fmt_desc_get(pix_fmt); 363 364 if(desc == NULL) { 365 return false; 366 } 367 368 if(pix_fmt == AV_PIX_FMT_PAL8) { 369 return true; 370 } 371 372 return (desc->flags & AV_PIX_FMT_FLAG_ALPHA) ? true : false; 373 } 374 375 static bool ffmpeg_pix_fmt_is_yuv(enum AVPixelFormat pix_fmt) 376 { 377 const AVPixFmtDescriptor * desc = av_pix_fmt_desc_get(pix_fmt); 378 379 if(desc == NULL) { 380 return false; 381 } 382 383 return !(desc->flags & AV_PIX_FMT_FLAG_RGB) && desc->nb_components >= 2; 384 } 385 386 static int ffmpeg_output_video_frame(struct ffmpeg_context_s * ffmpeg_ctx) 387 { 388 int ret = -1; 389 390 int width = ffmpeg_ctx->video_dec_ctx->width; 391 int height = ffmpeg_ctx->video_dec_ctx->height; 392 AVFrame * frame = ffmpeg_ctx->frame; 393 394 if(frame->width != width 395 || frame->height != height 396 || frame->format != ffmpeg_ctx->video_dec_ctx->pix_fmt) { 397 398 /* To handle this change, one could call av_image_alloc again and 399 * decode the following frames into another rawvideo file. 400 */ 401 LV_LOG_ERROR("Width, height and pixel format have to be " 402 "constant in a rawvideo file, but the width, height or " 403 "pixel format of the input video changed:\n" 404 "old: width = %d, height = %d, format = %s\n" 405 "new: width = %d, height = %d, format = %s\n", 406 width, 407 height, 408 av_get_pix_fmt_name(ffmpeg_ctx->video_dec_ctx->pix_fmt), 409 frame->width, frame->height, 410 av_get_pix_fmt_name(frame->format)); 411 goto failed; 412 } 413 414 LV_LOG_TRACE("video_frame coded_n:%d", frame->coded_picture_number); 415 416 /* copy decoded frame to destination buffer: 417 * this is required since rawvideo expects non aligned data 418 */ 419 av_image_copy(ffmpeg_ctx->video_src_data, ffmpeg_ctx->video_src_linesize, 420 (const uint8_t **)(frame->data), frame->linesize, 421 ffmpeg_ctx->video_dec_ctx->pix_fmt, width, height); 422 423 if(ffmpeg_ctx->sws_ctx == NULL) { 424 int swsFlags = SWS_BILINEAR; 425 426 if(ffmpeg_pix_fmt_is_yuv(ffmpeg_ctx->video_dec_ctx->pix_fmt)) { 427 428 /* When the video width and height are not multiples of 8, 429 * and there is no size change in the conversion, 430 * a blurry screen will appear on the right side 431 * This problem was discovered in 2012 and 432 * continues to exist in version 4.1.3 in 2019 433 * This problem can be avoided by increasing SWS_ACCURATE_RND 434 */ 435 if((width & 0x7) || (height & 0x7)) { 436 LV_LOG_WARN("The width(%d) and height(%d) the image " 437 "is not a multiple of 8, " 438 "the decoding speed may be reduced", 439 width, height); 440 swsFlags |= SWS_ACCURATE_RND; 441 } 442 } 443 444 ffmpeg_ctx->sws_ctx = sws_getContext( 445 width, height, ffmpeg_ctx->video_dec_ctx->pix_fmt, 446 width, height, ffmpeg_ctx->video_dst_pix_fmt, 447 swsFlags, 448 NULL, NULL, NULL); 449 } 450 451 if(!ffmpeg_ctx->has_alpha) { 452 int lv_linesize = sizeof(lv_color_t) * width; 453 int dst_linesize = ffmpeg_ctx->video_dst_linesize[0]; 454 if(dst_linesize != lv_linesize) { 455 LV_LOG_WARN("ffmpeg linesize = %d, but lvgl image require %d", 456 dst_linesize, 457 lv_linesize); 458 ffmpeg_ctx->video_dst_linesize[0] = lv_linesize; 459 } 460 } 461 462 ret = sws_scale( 463 ffmpeg_ctx->sws_ctx, 464 (const uint8_t * const *)(ffmpeg_ctx->video_src_data), 465 ffmpeg_ctx->video_src_linesize, 466 0, 467 height, 468 ffmpeg_ctx->video_dst_data, 469 ffmpeg_ctx->video_dst_linesize); 470 471 failed: 472 return ret; 473 } 474 475 static int ffmpeg_decode_packet(AVCodecContext * dec, const AVPacket * pkt, 476 struct ffmpeg_context_s * ffmpeg_ctx) 477 { 478 int ret = 0; 479 480 /* submit the packet to the decoder */ 481 ret = avcodec_send_packet(dec, pkt); 482 if(ret < 0) { 483 LV_LOG_ERROR("Error submitting a packet for decoding (%s)", 484 av_err2str(ret)); 485 return ret; 486 } 487 488 /* get all the available frames from the decoder */ 489 while(ret >= 0) { 490 ret = avcodec_receive_frame(dec, ffmpeg_ctx->frame); 491 if(ret < 0) { 492 493 /* those two return values are special and mean there is 494 * no output frame available, 495 * but there were no errors during decoding 496 */ 497 if(ret == AVERROR_EOF || ret == AVERROR(EAGAIN)) { 498 return 0; 499 } 500 501 LV_LOG_ERROR("Error during decoding (%s)", av_err2str(ret)); 502 return ret; 503 } 504 505 /* write the frame data to output file */ 506 if(dec->codec->type == AVMEDIA_TYPE_VIDEO) { 507 ret = ffmpeg_output_video_frame(ffmpeg_ctx); 508 } 509 510 av_frame_unref(ffmpeg_ctx->frame); 511 if(ret < 0) { 512 LV_LOG_WARN("ffmpeg_decode_packet ended %d", ret); 513 return ret; 514 } 515 } 516 517 return 0; 518 } 519 520 static int ffmpeg_open_codec_context(int * stream_idx, 521 AVCodecContext ** dec_ctx, AVFormatContext * fmt_ctx, 522 enum AVMediaType type) 523 { 524 int ret; 525 int stream_index; 526 AVStream * st; 527 AVCodec * dec = NULL; 528 AVDictionary * opts = NULL; 529 530 ret = av_find_best_stream(fmt_ctx, type, -1, -1, NULL, 0); 531 if(ret < 0) { 532 LV_LOG_ERROR("Could not find %s stream in input file", 533 av_get_media_type_string(type)); 534 return ret; 535 } 536 else { 537 stream_index = ret; 538 st = fmt_ctx->streams[stream_index]; 539 540 /* find decoder for the stream */ 541 dec = avcodec_find_decoder(st->codecpar->codec_id); 542 if(dec == NULL) { 543 LV_LOG_ERROR("Failed to find %s codec", 544 av_get_media_type_string(type)); 545 return AVERROR(EINVAL); 546 } 547 548 /* Allocate a codec context for the decoder */ 549 *dec_ctx = avcodec_alloc_context3(dec); 550 if(*dec_ctx == NULL) { 551 LV_LOG_ERROR("Failed to allocate the %s codec context", 552 av_get_media_type_string(type)); 553 return AVERROR(ENOMEM); 554 } 555 556 /* Copy codec parameters from input stream to output codec context */ 557 if((ret = avcodec_parameters_to_context(*dec_ctx, st->codecpar)) < 0) { 558 LV_LOG_ERROR( 559 "Failed to copy %s codec parameters to decoder context", 560 av_get_media_type_string(type)); 561 return ret; 562 } 563 564 /* Init the decoders */ 565 if((ret = avcodec_open2(*dec_ctx, dec, &opts)) < 0) { 566 LV_LOG_ERROR("Failed to open %s codec", 567 av_get_media_type_string(type)); 568 return ret; 569 } 570 571 *stream_idx = stream_index; 572 } 573 574 return 0; 575 } 576 577 static int ffmpeg_get_img_header(const char * filepath, 578 lv_img_header_t * header) 579 { 580 int ret = -1; 581 582 AVFormatContext * fmt_ctx = NULL; 583 AVCodecContext * video_dec_ctx = NULL; 584 int video_stream_idx; 585 586 /* open input file, and allocate format context */ 587 if(avformat_open_input(&fmt_ctx, filepath, NULL, NULL) < 0) { 588 LV_LOG_ERROR("Could not open source file %s", filepath); 589 goto failed; 590 } 591 592 /* retrieve stream information */ 593 if(avformat_find_stream_info(fmt_ctx, NULL) < 0) { 594 LV_LOG_ERROR("Could not find stream information"); 595 goto failed; 596 } 597 598 if(ffmpeg_open_codec_context(&video_stream_idx, &video_dec_ctx, 599 fmt_ctx, AVMEDIA_TYPE_VIDEO) 600 >= 0) { 601 bool has_alpha = ffmpeg_pix_fmt_has_alpha(video_dec_ctx->pix_fmt); 602 603 /* allocate image where the decoded image will be put */ 604 header->w = video_dec_ctx->width; 605 header->h = video_dec_ctx->height; 606 header->always_zero = 0; 607 header->cf = (has_alpha ? LV_IMG_CF_TRUE_COLOR_ALPHA : LV_IMG_CF_TRUE_COLOR); 608 609 ret = 0; 610 } 611 612 failed: 613 avcodec_free_context(&video_dec_ctx); 614 avformat_close_input(&fmt_ctx); 615 616 return ret; 617 } 618 619 static int ffmpeg_get_frame_refr_period(struct ffmpeg_context_s * ffmpeg_ctx) 620 { 621 int avg_frame_rate_num = ffmpeg_ctx->video_stream->avg_frame_rate.num; 622 if(avg_frame_rate_num > 0) { 623 int period = 1000 * (int64_t)ffmpeg_ctx->video_stream->avg_frame_rate.den 624 / avg_frame_rate_num; 625 return period; 626 } 627 628 return -1; 629 } 630 631 static int ffmpeg_update_next_frame(struct ffmpeg_context_s * ffmpeg_ctx) 632 { 633 int ret = 0; 634 635 while(1) { 636 637 /* read frames from the file */ 638 if(av_read_frame(ffmpeg_ctx->fmt_ctx, &(ffmpeg_ctx->pkt)) >= 0) { 639 bool is_image = false; 640 641 /* check if the packet belongs to a stream we are interested in, 642 * otherwise skip it 643 */ 644 if(ffmpeg_ctx->pkt.stream_index == ffmpeg_ctx->video_stream_idx) { 645 ret = ffmpeg_decode_packet(ffmpeg_ctx->video_dec_ctx, 646 &(ffmpeg_ctx->pkt), ffmpeg_ctx); 647 is_image = true; 648 } 649 650 av_packet_unref(&(ffmpeg_ctx->pkt)); 651 652 if(ret < 0) { 653 LV_LOG_WARN("video frame is empty %d", ret); 654 break; 655 } 656 657 /* Used to filter data that is not an image */ 658 if(is_image) { 659 break; 660 } 661 } 662 else { 663 ret = -1; 664 break; 665 } 666 } 667 668 return ret; 669 } 670 671 struct ffmpeg_context_s * ffmpeg_open_file(const char * path) 672 { 673 if(path == NULL || strlen(path) == 0) { 674 LV_LOG_ERROR("file path is empty"); 675 return NULL; 676 } 677 678 struct ffmpeg_context_s * ffmpeg_ctx = calloc(1, sizeof(struct ffmpeg_context_s)); 679 680 if(ffmpeg_ctx == NULL) { 681 LV_LOG_ERROR("ffmpeg_ctx malloc failed"); 682 goto failed; 683 } 684 685 /* open input file, and allocate format context */ 686 687 if(avformat_open_input(&(ffmpeg_ctx->fmt_ctx), path, NULL, NULL) < 0) { 688 LV_LOG_ERROR("Could not open source file %s", path); 689 goto failed; 690 } 691 692 /* retrieve stream information */ 693 694 if(avformat_find_stream_info(ffmpeg_ctx->fmt_ctx, NULL) < 0) { 695 LV_LOG_ERROR("Could not find stream information"); 696 goto failed; 697 } 698 699 if(ffmpeg_open_codec_context( 700 &(ffmpeg_ctx->video_stream_idx), 701 &(ffmpeg_ctx->video_dec_ctx), 702 ffmpeg_ctx->fmt_ctx, AVMEDIA_TYPE_VIDEO) 703 >= 0) { 704 ffmpeg_ctx->video_stream = ffmpeg_ctx->fmt_ctx->streams[ffmpeg_ctx->video_stream_idx]; 705 706 ffmpeg_ctx->has_alpha = ffmpeg_pix_fmt_has_alpha(ffmpeg_ctx->video_dec_ctx->pix_fmt); 707 708 ffmpeg_ctx->video_dst_pix_fmt = (ffmpeg_ctx->has_alpha ? AV_PIX_FMT_BGRA : AV_PIX_FMT_TRUE_COLOR); 709 } 710 711 #if LV_FFMPEG_AV_DUMP_FORMAT != 0 712 /* dump input information to stderr */ 713 av_dump_format(ffmpeg_ctx->fmt_ctx, 0, path, 0); 714 #endif 715 716 if(ffmpeg_ctx->video_stream == NULL) { 717 LV_LOG_ERROR("Could not find video stream in the input, aborting"); 718 goto failed; 719 } 720 721 return ffmpeg_ctx; 722 723 failed: 724 ffmpeg_close(ffmpeg_ctx); 725 return NULL; 726 } 727 728 static int ffmpeg_image_allocate(struct ffmpeg_context_s * ffmpeg_ctx) 729 { 730 int ret; 731 732 /* allocate image where the decoded image will be put */ 733 ret = av_image_alloc( 734 ffmpeg_ctx->video_src_data, 735 ffmpeg_ctx->video_src_linesize, 736 ffmpeg_ctx->video_dec_ctx->width, 737 ffmpeg_ctx->video_dec_ctx->height, 738 ffmpeg_ctx->video_dec_ctx->pix_fmt, 739 4); 740 741 if(ret < 0) { 742 LV_LOG_ERROR("Could not allocate src raw video buffer"); 743 return ret; 744 } 745 746 LV_LOG_INFO("alloc video_src_bufsize = %d", ret); 747 748 ret = av_image_alloc( 749 ffmpeg_ctx->video_dst_data, 750 ffmpeg_ctx->video_dst_linesize, 751 ffmpeg_ctx->video_dec_ctx->width, 752 ffmpeg_ctx->video_dec_ctx->height, 753 ffmpeg_ctx->video_dst_pix_fmt, 754 4); 755 756 if(ret < 0) { 757 LV_LOG_ERROR("Could not allocate dst raw video buffer"); 758 return ret; 759 } 760 761 LV_LOG_INFO("allocate video_dst_bufsize = %d", ret); 762 763 ffmpeg_ctx->frame = av_frame_alloc(); 764 765 if(ffmpeg_ctx->frame == NULL) { 766 LV_LOG_ERROR("Could not allocate frame"); 767 return -1; 768 } 769 770 /* initialize packet, set data to NULL, let the demuxer fill it */ 771 av_init_packet(&ffmpeg_ctx->pkt); 772 ffmpeg_ctx->pkt.data = NULL; 773 ffmpeg_ctx->pkt.size = 0; 774 775 return 0; 776 } 777 778 static void ffmpeg_close_src_ctx(struct ffmpeg_context_s * ffmpeg_ctx) 779 { 780 avcodec_free_context(&(ffmpeg_ctx->video_dec_ctx)); 781 avformat_close_input(&(ffmpeg_ctx->fmt_ctx)); 782 av_frame_free(&(ffmpeg_ctx->frame)); 783 if(ffmpeg_ctx->video_src_data[0] != NULL) { 784 av_free(ffmpeg_ctx->video_src_data[0]); 785 ffmpeg_ctx->video_src_data[0] = NULL; 786 } 787 } 788 789 static void ffmpeg_close_dst_ctx(struct ffmpeg_context_s * ffmpeg_ctx) 790 { 791 if(ffmpeg_ctx->video_dst_data[0] != NULL) { 792 av_free(ffmpeg_ctx->video_dst_data[0]); 793 ffmpeg_ctx->video_dst_data[0] = NULL; 794 } 795 } 796 797 static void ffmpeg_close(struct ffmpeg_context_s * ffmpeg_ctx) 798 { 799 if(ffmpeg_ctx == NULL) { 800 LV_LOG_WARN("ffmpeg_ctx is NULL"); 801 return; 802 } 803 804 sws_freeContext(ffmpeg_ctx->sws_ctx); 805 ffmpeg_close_src_ctx(ffmpeg_ctx); 806 ffmpeg_close_dst_ctx(ffmpeg_ctx); 807 free(ffmpeg_ctx); 808 809 LV_LOG_INFO("ffmpeg_ctx closed"); 810 } 811 812 static void lv_ffmpeg_player_frame_update_cb(lv_timer_t * timer) 813 { 814 lv_obj_t * obj = (lv_obj_t *)timer->user_data; 815 lv_ffmpeg_player_t * player = (lv_ffmpeg_player_t *)obj; 816 817 if(!player->ffmpeg_ctx) { 818 return; 819 } 820 821 int has_next = ffmpeg_update_next_frame(player->ffmpeg_ctx); 822 823 if(has_next < 0) { 824 lv_ffmpeg_player_set_cmd(obj, player->auto_restart ? LV_FFMPEG_PLAYER_CMD_START : LV_FFMPEG_PLAYER_CMD_STOP); 825 return; 826 } 827 828 #if LV_COLOR_DEPTH != 32 829 if(player->ffmpeg_ctx->has_alpha) { 830 convert_color_depth((uint8_t *)(player->imgdsc.data), 831 player->imgdsc.header.w * player->imgdsc.header.h); 832 } 833 #endif 834 835 lv_img_cache_invalidate_src(lv_img_get_src(obj)); 836 lv_obj_invalidate(obj); 837 } 838 839 static void lv_ffmpeg_player_constructor(const lv_obj_class_t * class_p, 840 lv_obj_t * obj) 841 { 842 LV_TRACE_OBJ_CREATE("begin"); 843 844 lv_ffmpeg_player_t * player = (lv_ffmpeg_player_t *)obj; 845 846 player->auto_restart = false; 847 player->ffmpeg_ctx = NULL; 848 player->timer = lv_timer_create(lv_ffmpeg_player_frame_update_cb, 849 FRAME_DEF_REFR_PERIOD, obj); 850 lv_timer_pause(player->timer); 851 852 LV_TRACE_OBJ_CREATE("finished"); 853 } 854 855 static void lv_ffmpeg_player_destructor(const lv_obj_class_t * class_p, 856 lv_obj_t * obj) 857 { 858 LV_TRACE_OBJ_CREATE("begin"); 859 860 lv_ffmpeg_player_t * player = (lv_ffmpeg_player_t *)obj; 861 862 if(player->timer) { 863 lv_timer_del(player->timer); 864 player->timer = NULL; 865 } 866 867 lv_img_cache_invalidate_src(lv_img_get_src(obj)); 868 869 ffmpeg_close(player->ffmpeg_ctx); 870 player->ffmpeg_ctx = NULL; 871 872 LV_TRACE_OBJ_CREATE("finished"); 873 } 874 875 #endif /*LV_USE_FFMPEG*/