10.1_demo/src/e_player_list.c

848 lines
26 KiB
C
Raw Normal View History

// e_player_list.c
#include "e_player_list.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "e_logger.h"
#include <sys/time.h>
#include "e_conf.h"
#include <errno.h>
#define GET_SCR_WIDTH() (LV_USE_HOR_SIZE)
#define GET_SCR_HEIGHT() (LV_USE_VER_SIZE)
#define USEC_TO_SECONDS (1000 * 1000)
#define TOLERANCE_MS 200 // 误差容忍度200ms
#define retry_max 5 // 播放失败最大重试次数
#define USEC_TO_MS 1000 // 微秒转毫秒
#define MS_TO_USEC 1000 // 毫秒转微秒
#define DECODE_REDUNDANCY_MS 1500 // 解码性能差设备的时间冗余 (1 秒)
static bool sync_play = true; // 是否开启同步播放
static int retry_count = 0;
extern int g_screen_rotation;
// ======================== 内部函数声明 ========================
static void *player_thread_func(void *arg);
static void dis_player_hole(int display_idx);
static int my_play_callback(void *user, int evt, void *info);
static int play_video(VideoPlayer *video_player, const MediaPath *file_path);
static void play_error(VideoPlayer *video_player, const int code);
static void xos_player_set_volume(void *player, int volume);
extern void fbdev_set_hole(int x, int y, int width, int height);
extern void fbdev2_set_hole(int x, int y, int width, int height);
// ======================== 播放器API实现 ========================
QUA_BOOL is_stop = QUA_FALSE;
VideoPlayer *video_player_init(int display_idx)
{
VideoPlayer *player = calloc(1, sizeof(VideoPlayer));
if (!player)
return NULL;
player->display_idx = display_idx;
snprintf(player->display, sizeof(player->display), "id:display%d", display_idx);
player->media_paths = calloc(MAX_PLAYLIST_ITEMS, sizeof(MediaPath *));
if (!player->media_paths)
{
LOGE("播放列表初始化失败:内存分配失败");
free(player);
return NULL;
}
pthread_mutex_init(&player->playlist_mutex, NULL);
pthread_mutex_init(&player->play_mutex, NULL);
pthread_cond_init(&player->play_cond, NULL);
return player;
}
// 设置是否开启同步播放
void video_player_set_sync_play(bool sync)
{
sync_play = sync;
}
/**
* video_player
*
*/
void video_player_close(VideoPlayer *video_player)
{
if (!video_player)
return;
video_player->first_play = true;
if (video_player->stop_requested)
{
// 当下载失败后。黑洞已打开,但是视频并没有开始播放,因此此处添加关闭黑洞
dis_player_hole(video_player->display_idx);
return;
}
LOGI("开始关闭播放器");
// 停止播放线程
video_player->stop_requested = true;
// 发送条件变量信号通知播放线程停止
pthread_mutex_lock(&video_player->play_mutex);
pthread_cond_signal(&video_player->play_cond);
pthread_mutex_unlock(&video_player->play_mutex);
// 等待播放线程结束,设置超时避免死锁
if (video_player->thread_running)
{
LOGI("等待播放线程结束");
struct timespec timeout;
clock_gettime(CLOCK_REALTIME, &timeout);
timeout.tv_sec += 3; // 设置3秒超时
int join_result = pthread_timedjoin_np(video_player->player_thread, NULL, &timeout);
if (join_result == ETIMEDOUT)
{
LOGE("播放线程结束超时,强制取消线程");
pthread_cancel(video_player->player_thread);
}
video_player->thread_running = false;
LOGI("播放线程已结束");
}
// 安全销毁播放器
if (video_player->player)
{
LOGI("安全销毁播放器");
// 先尝试正常停止
int stop_result = qua_mm_player_stop(video_player->player);
if (stop_result != 0)
{
LOGE("播放器stop失败ret=%d尝试强制重置", stop_result);
qua_mm_player_reset(video_player->player);
}
// 等待一小段时间确保清理完成
usleep(100 * 1000); // 100ms
qua_mm_player_destroy(video_player->player);
video_player->player = NULL;
LOGI("播放器销毁完成");
}
// 清空播放列表
video_player_clear_playlist(video_player);
LOGI("关闭黑洞显示");
// 关闭黑洞
dis_player_hole(video_player->display_idx);
LOGI("播放器关闭完成");
}
/**
*
*/
void video_player_destroy(VideoPlayer *video_player)
{
if (!video_player)
return;
// 先关闭播放器
if (!video_player->stop_requested)
{
video_player_close(video_player);
}
// 清理播放列表
pthread_mutex_lock(&video_player->playlist_mutex);
for (int i = 0; i < video_player->media_count; i++)
{
if (video_player->media_paths[i])
{
free(video_player->media_paths[i]);
video_player->media_paths[i] = NULL;
}
}
free(video_player->media_paths); // 释放二级指针数组
video_player->media_paths = NULL;
video_player->media_count = 0;
pthread_mutex_unlock(&video_player->playlist_mutex);
// 确保播放线程已停止
video_player->stop_requested = true;
if (video_player->thread_running)
{
pthread_join(video_player->player_thread, NULL);
}
// 确保播放器已清理
if (video_player->player)
{
LOGI("video_player_destroy中清理剩余播放器");
qua_mm_player_stop(video_player->player);
qua_mm_player_destroy(video_player->player);
video_player->player = NULL;
}
// 关闭黑洞
dis_player_hole(video_player->display_idx);
pthread_mutex_destroy(&video_player->playlist_mutex);
free(video_player);
}
// ======================== 线程安全的播放列表管理 ========================
void video_player_add_item(VideoPlayer *player, const MediaPath *local_path)
{
if (!player || !local_path)
return;
pthread_mutex_lock(&player->playlist_mutex);
if (player->media_count < MAX_PLAYLIST_ITEMS)
{
player->media_paths[player->media_count++] = local_path;
}
pthread_mutex_unlock(&player->playlist_mutex);
}
void video_player_clear_playlist(VideoPlayer *player)
{
if (!player)
return;
pthread_mutex_lock(&player->playlist_mutex);
for (int i = 0; i < player->media_count; i++)
{
if (player->media_paths[i])
{
free(player->media_paths[i]);
player->media_paths[i] = NULL;
}
}
player->media_count = 0;
player->current_index = 0;
player->first_play = true;
pthread_mutex_unlock(&player->playlist_mutex);
}
void video_player_set_double_buffer(VideoPlayer *video_player)
{
if (!video_player)
return;
video_player_clear_playlist(video_player);
// video_player->media_count = 0;
// video_player->current_index = 0;
}
void video_player_set_size(VideoPlayer *video_player, e_player_area area)
{
if (!video_player)
return;
if (area.width > GET_SCR_WIDTH())
{
area.width = GET_SCR_WIDTH();
}
if (area.height > GET_SCR_HEIGHT())
{
area.height = GET_SCR_HEIGHT();
}
video_player->area = area;
// video_player_set_hole(video_player);
}
// ======================== 播放控制 ========================
// 获取毫秒时间戳
long long get_current_time_ms()
{
struct timespec ts;
// 获取单调时钟(自系统启动后流逝的时间,不受系统时间修改影响)
if (clock_gettime(CLOCK_REALTIME, &ts) != 0)
{
LOGE("clock_gettime failed");
return 0;
}
return (long long)ts.tv_sec * 1000 + ts.tv_nsec / 1000000; // 转换为毫秒
}
int video_player_play(VideoPlayer *player)
{
if (!player)
return -1;
// 确保有可播放的内容
pthread_mutex_lock(&player->playlist_mutex);
bool has_media = (player->media_count > 0);
pthread_mutex_unlock(&player->playlist_mutex);
if (!has_media)
{
LOGW("播放列表为空");
return -1;
}
if (player->thread_running)
{
LOGW("播放线程已在运行");
return -1;
}
player->stop_requested = false;
player->first_play = true;
// player->actual_play_ms = 0; // 重置播放耗时统计
if (pthread_create(&player->player_thread, NULL, player_thread_func, player) == 0)
{
player->thread_running = true;
LOGI("播放线程已启动");
return 0;
}
else
{
LOGE("播放线程创建失败");
return -1;
}
}
void video_player_next(VideoPlayer *player)
{
if (!player)
return;
pthread_mutex_lock(&player->playlist_mutex);
if (player->media_count > 0)
{
player->current_index = (player->current_index + 1) % player->media_count;
}
pthread_mutex_unlock(&player->playlist_mutex);
}
void video_player_set_hole(VideoPlayer *video_player)
{
if (!video_player)
return;
// 根据屏幕旋转调整挖洞区域坐标
int x = video_player->area.x;
int y = video_player->area.y;
int width = video_player->area.width;
int height = video_player->area.height;
// 获取实际屏幕尺寸
int actual_scr_width, actual_scr_height;
if (g_screen_rotation == 1 || g_screen_rotation == 3)
{ // 90度或270度旋转
actual_scr_width = GET_SCR_HEIGHT();
actual_scr_height = GET_SCR_WIDTH();
}
else
{ // 0度或180度旋转
actual_scr_width = GET_SCR_WIDTH();
actual_scr_height = GET_SCR_HEIGHT();
}
// 根据旋转角度调整坐标
switch (g_screen_rotation)
{
case 1: // 90度旋转(x,y) -> (y, height-1-(x+width-1), width, height) -> (height, width)
{
int temp_x = y;
int temp_y = actual_scr_height - 1 - (x + width - 1);
int temp_width = height;
int temp_height = width;
x = temp_x;
y = temp_y;
width = temp_width;
height = temp_height;
}
break;
case 2: // 180度旋转(x,y) -> (width-1-(x+width-1), height-1-(y+height-1)) = (width-x-width, height-y-height)
x = actual_scr_width - (x + width);
y = actual_scr_height - (y + height);
break;
case 3: // 270度旋转(x,y) -> (width-1-(y+height-1), x, height, width) -> (height, width)
{
int temp_x = actual_scr_width - 1 - (y + height - 1);
int temp_y = x;
int temp_width = height;
int temp_height = width;
x = temp_x;
y = temp_y;
width = temp_width;
height = temp_height;
}
break;
case 0: // 0度无旋转
default:
break;
}
if (video_player->display_idx == 0)
{
LOGD("设置视频挖洞区域。x=%d,y=%d,w=%d,h=%d", x, y, width, height);
fbdev_set_hole(x, y, width, height);
}
else
{
LOGD("设置视频挖洞区域。x=%d,y=%d,w=%d,h=%d", x, y, width, height);
fbdev2_set_hole(x, y, width, height);
}
}
// ======================== 内部实现 ========================
static void *player_thread_func(void *arg)
{
VideoPlayer *player = (VideoPlayer *)arg;
while (!player->stop_requested)
{
pthread_mutex_lock(&player->playlist_mutex);
if (player->media_count == 0)
{
pthread_mutex_unlock(&player->playlist_mutex);
LOGW("播放列表为空,停止播放");
break;
}
int index = player->current_index % player->media_count;
MediaPath *media_path = player->media_paths[index];
// char file_path[MAX_URL_LEN];
// strncpy(file_path, player->media_paths[index], MAX_URL_LEN);
pthread_mutex_unlock(&player->playlist_mutex);
if (!media_path)
{
player->current_index = (player->current_index + 1) % player->media_count;
continue;
}
// LOGI("开始播放第 %d 个文件: %s", index, file_path);
is_stop = QUA_FALSE;
int ret = play_video(player, media_path);
if (player->first_play)
{
player->first_play = false;
}
// player->start_time_ms=0; // 重置播放开始时间
if (ret != 0)
{
retry_count++;
if (retry_count > retry_max)
{
// if(player->media_count==1){
// LOGE("播放失败,超过最大重试次数%d:%s",retry_count,file_path);
// break;
// }
LOGE("播放失败,超过最大重试次数%d:%s", retry_count, media_path->path);
break;
}
// else{
LOGE("播放失败,等待1秒后重试%d:%s", retry_count, media_path->path);
// sleep(2);
// }
sleep(1);
// continue;
}
else
{
retry_count = 0;
// LOGD("视频播放完成,理论时长:% lldms实际耗时:% lldms显示器 % d",
// player->video_duration_ms, player->actual_play_ms, player->display_idx);
}
// 播放完成后切换下一个(根据双屏冗余调整切换时机)
// #if DISP_COUNT == 2
// // 双屏模式:确保所有设备都播放完成后再切换(等待冗余时间)
// if (sync_play){
// long long wait_switch_ms = (player->video_duration_ms + DECODE_REDUNDANCY_MS) - player->actual_play_ms;
// if (wait_switch_ms > 0)
// {
// LOGD("双屏模式等待冗余时间:% lldms显示器 % d", wait_switch_ms, player->display_idx);
// usleep(wait_switch_ms * MS_TO_USEC);
// }
// }
// #endif
// 播放完成或失败后切换下一个
player->current_index = (player->current_index + 1) % player->media_count;
// LOGI("开始切换下一个视频");
}
player->thread_running = false;
LOGW("播放线程退出(显示器 % d", player->display_idx);
return NULL;
}
// 计算显示区域根据视频比例和屏幕比例计算显示区域的大小和位置。视频大小必须为8的倍数
static void calculate_display_rect(int img_width, int img_height, lv_area_t *area, qua_rect_t *rect, bool auto_center)
{
int is_screen_landscape = GET_SCR_WIDTH() > GET_SCR_HEIGHT();
int is_image_landscape = img_width > img_height;
int is_adaptive = (is_image_landscape != is_screen_landscape);
// LV_LOG_USER("area [%d %d] area rect size [%d %d]", area->x1, area->y1, area->x2, area->y2);
// LV_LOG_USER("img_width: %d, img_height:%d\n", img_width, img_height);
rect->x = area->x1;
rect->y = area->y1;
rect->width = area->x2 - area->x1 + 1;
rect->height = area->y2 - area->y1 + 1;
if (auto_center)
{
if (true)
{
float screen_ratio = (float)GET_SCR_WIDTH() / GET_SCR_HEIGHT();
float image_ratio = (float)img_width / img_height;
// LV_LOG_USER("screen_ratio =%f,image_ratio=%d", screen_ratio, image_ratio);
if (screen_ratio > image_ratio)
{
rect->width = GET_SCR_HEIGHT() * img_width / img_height;
rect->height = GET_SCR_HEIGHT();
rect->x = (GET_SCR_WIDTH() - rect->width) / 2;
rect->y = 0;
if (rect->x > 0 && rect->x % 2 > 0)
rect->x += 1;
}
else
{
rect->width = GET_SCR_WIDTH();
rect->height = GET_SCR_WIDTH() * img_height / img_width;
rect->x = 0;
rect->y = (GET_SCR_HEIGHT() - rect->height) / 2;
if (rect->y > 0 && rect->y % 2 > 0)
rect->y += 1;
// rect->height = (area->y2- area->y1)/ 4 *4;
// LV_LOG_USER("#######");
}
}
}
else
{
rect->x = area->x1 / 2 * 2;
rect->y = area->y1 / 2 * 2;
rect->width = area->x2 / 8 * 8;
rect->height = area->y2 / 8 * 8;
// LV_LOG_USER("@@@@@@@@@");
}
rect->width = rect->width / 8 * 8;
rect->height = rect->height / 8 * 8;
LOGD("display rect [%d %d %d %d]", rect->x, rect->y, rect->width, rect->height);
}
static int play_video(VideoPlayer *video_player, const MediaPath *media_path)
{
void *player = NULL;
QUA_S32 ret = 0;
QUA_BOOL pos_cb = QUA_TRUE;
if (!video_player->player)
{
if (video_player->display_idx == 0)
{
player = qua_mm_player_create("e_video_play");
}
else
{
player = qua_mm_player_create("e_video_play1");
}
if (player)
{
// LOGI("diaplayer name %s", video_player->display);
qua_mm_player_set_parameter(player, KEY_PARAMETER_VO_DISPLAY_ID, (QUA_VOID_PTR)video_player->display);
// 设置视频旋转角度
// qua_rotate_t rotate = 2;
// qua_mm_player_set_parameter(player, KEY_PARAMETER_VO_ROTATE, (QUA_VOID_PTR)&rotate);
qua_mm_player_set_parameter(player, KEY_PARAMETER_VO_ROTATE, (QUA_VOID_PTR)&g_screen_rotation);
xos_player_set_volume(player, 0);
qua_mm_player_set_loop(player, QUA_FALSE);
video_player->player = player;
}
}
else
{
player = video_player->player;
// LOGI("reset player");
qua_mm_player_reset(player);
}
if (!player)
{
LOGE("创建播放器失败");
return -1;
}
ret = qua_mm_player_set_data_source(player, media_path->path);
if (ret != 0)
{
LOGE("设置播放源失败 %s", media_path->path);
goto fail;
}
qua_size_t size;
qua_mm_player_get_parameter(player, KEY_PARAMETER_VIDEO_SIZE, (QUA_VOID_PTR)&size);
// LOGI("获取到视频分辨率 %dx%d", size.width, size.height);
if (size.width * size.height > 1920 * 1080)
{
LOGE("视频分辨率超过1920*1080");
goto fail;
}
e_player_area video_area = video_player->area;
lv_area_t area = {0};
area.x1 = video_area.x;
area.x2 = video_area.width;
area.y1 = video_area.y;
area.y2 = video_area.height;
qua_rect_t rect = {0};
calculate_display_rect(size.width, size.height, &area, &rect, false);
qua_rect_t chn_rect;
chn_rect.x = 0;
chn_rect.y = 0;
chn_rect.width = GET_SCR_WIDTH();
chn_rect.height = GET_SCR_HEIGHT();
qua_mm_player_set_parameter(player, KEY_PARAMETER_VO_DISPLAY_RECT, (QUA_VOID_PTR)&chn_rect);
// video 大小
qua_mm_player_set_parameter(player, KEY_PARAMETER_VO_CHN_RECT, (QUA_VOID_PTR)&rect);
ret = qua_mm_player_prepare(player);
if (ret != 0)
{
LOGE("准备播放失败. ret=%d", ret);
goto fail;
}
ret = qua_mm_player_set_callback(player, my_play_callback, video_player);
if (ret != 0)
{
LOGE("设置回调失败. ret=%d", ret);
goto fail;
}
// qua_mm_player_set_parameter(player, KEY_PARAMETER_SET_CURRENT_POSITION_CALLBACK, (QUA_VOID *)&pos_cb);
// 获取视频时长并计算同步起始时间
long long video_duration_us = qua_mm_player_get_durationUs(player); // 转换为毫秒
video_player->video_duration_ms = video_duration_us / 1000; // 转换为毫秒
LOGD("获取视频时长:% lldms显示器 % d", video_player->video_duration_ms, video_player->display_idx);
// 同步播放处理
// QUA_S32 qua_mm_player_seek(QUA_VOID* player, QUA_U64 timeUs);
long long play_position_ms = 0;
if (sync_play && video_player->media_count == 1)
{
// long long currentTime=get_current_time_ms();
// long long minuteMillis= video_player->video_duration_ms+1000;
// if (video_player->first_play)
// {
// // 首次开机时 系统时间尚未校时,因此可能计算的位置不对
// long long viode_duration_ms = video_player->video_duration_ms + 600;
// long long positionMs = get_current_time_ms() % viode_duration_ms; // 当前应该播放的位置(毫秒)
// qua_mm_player_seek(player, positionMs * 1000); // 转换为微秒
// play_position_ms = positionMs; // 使播放器提前结束,防止下次播放时错过开始时间
// }
// else
// {
// long long viode_duration_ms= video_player->video_duration_ms+2000;
long long viode_duration_ms = video_player->video_duration_ms + 1000;
// long long positionMs = get_current_time_ms() % viode_duration_ms;// 当前应该播放的位置(毫秒)
long long t_remainder = get_current_time_ms() % viode_duration_ms;
LOGI("距离视频开始:%lld", t_remainder);
long long tolerance = 300;
while (!is_stop && !video_player->stop_requested)
{
long long currentTime = get_current_time_ms();
long long remainder = currentTime % viode_duration_ms;
if (remainder <= tolerance || (viode_duration_ms - remainder) <= tolerance)
{
break; // 开始播放
}
usleep(50 * MS_TO_USEC);
}
//}
}
video_player_set_hole(video_player);
ret = qua_mm_player_start(player);
if (ret != 0)
{
LOGE("播放器启动失败ret=% d显示器 % d", ret, video_player->display_idx);
goto fail;
}
if (play_position_ms > 0)
{
video_player->last_play_time_ms = get_current_time_ms() - play_position_ms;
}
else
{
video_player->last_play_time_ms = get_current_time_ms(); // 记录播放开始时间
}
// 计算结束时间
// long long end_time = get_current_time_ms() + video_player->video_duration_ms;
long long end_time = video_player->last_play_time_ms + video_player->video_duration_ms;
pthread_mutex_lock(&video_player->play_mutex);
while (get_current_time_ms() < end_time && !video_player->stop_requested)
{
int status = pthread_cond_timedwait(&video_player->play_cond, &video_player->play_mutex, (const struct timespec *)&(struct timespec){.tv_sec = end_time / 1000, .tv_nsec = (end_time % 1000) * 1000000});
if (status == ETIMEDOUT)
{
break;
}
}
pthread_mutex_unlock(&video_player->play_mutex);
// 发送播放通知
// event_play_start(media_path);
// usleep(video_duration_us);
// 使用循环检查方式替代usleep支持提前退出
// long long video_duration_ms = video_duration_us / 1000; // 转换为毫秒
// while (get_current_time_ms() - start_time < video_player->video_duration_ms&&!is_stop) {
// if (video_player->stop_requested) {
// LOGI("播放被提前终止(显示器 %d", video_player->display_idx);
// qua_mm_player_stop(player);
// return 0;
// }
// usleep(20 * 1000); // 20ms检查一次
// }
// 如果播放器中途被结束,则跳过
if (video_player->stop_requested)
{
return 0;
}
// LOGI("视频播放结束01");
// LOGI("~~~~~~~~~~~~~~~~视频播放结束~~~~~~~~~~~~~~~~");
ret = qua_mm_player_stop(player);
if (ret != 0)
{
LOGE("停止播放失败 ");
goto fail;
}
qua_mm_player_reset(player);
return 0;
fail:
if (player)
{
qua_mm_player_destroy(player);
player = NULL;
video_player->player = NULL;
}
return -1;
}
static void xos_player_set_volume(void *player, int volume)
{
// LV_LOG_USER("player volume is %d\n", volume);
qua_mm_player_set_volume(player, volume);
}
/**
*
*/
static int my_play_callback(void *user, int evt, void *info)
{
VideoPlayer *video_player = (VideoPlayer *)user;
if (evt == PLAYER_EVT_PLAYBACK_COMPLETE)
{
LOGD("收到播放完成回调(显示器 % d", video_player->display_idx);
is_stop = QUA_TRUE;
// pthread_mutex_lock(&video_player->is_stop_mutex);
// video_player->is_stop = QUA_TRUE;
// pthread_mutex_unlock(&video_player->is_stop_mutex);
}
else if (evt == PLAYER_EVT_CURRENT_POSITION)
{
// long pos = (long long)(*(QUA_U64 *)info) / USEC_TO_SECONDS;
// LOGI("video callback event POSITION %d", pos);
}
else
{
LOGD("收到播放器事件:% d显示器 % d", evt, video_player->display_idx);
}
return 0;
}
static void play_error(VideoPlayer *video_player, const int code)
{
LOGE("播放器出现异常,错误码: % d显示器 % d", code, video_player->display_idx);
}
static void dis_player_hole(int display_idx)
{
// 视频播放时,设置挖洞区域。
if (display_idx == 0)
{
fbdev_set_hole(0, 0, 0, 0);
}
else
{
fbdev2_set_hole(0, 0, 0, 0);
}
}
/*
*
*/
void video_check_play_state(VideoPlayer *player)
{
if (!player)
{
return;
}
if (player->thread_running)
{
LOGI("播放线程正在运行中...");
return;
}
// 判断播放列表是否为空、
pthread_mutex_lock(&player->playlist_mutex);
bool has_media = (player->media_count > 0);
pthread_mutex_unlock(&player->playlist_mutex);
if (!has_media)
{
LOGD("播放线程退出,播放列表为空");
return;
}
if (player->stop_requested)
{
LOGD("播放线程退出,用户主动调用退出");
return;
}
// 检查线程是否已结束
void *value = pthread_getspecific(player->player_thread);
if (value == (void *)1)
{
LOGI("播放器线程已退出");
// 计算距离上次播放时间
long long last_play_time_ms = player->last_play_time_ms;
long long current_time_ms = get_current_time_ms();
// 距离最后一次播放时间
long long time_diff_ms = current_time_ms - last_play_time_ms;
// 判断播放器是否停止;最后播放时间-当前播放视频的总时长+5秒。超过则说明播放意外退出。重新开始播放
// 如果距离上次播放时间小于视频总时长+5秒则等待5秒后重试
if (time_diff_ms > (player->video_duration_ms + 5000))
{
// 尝试开始播放
LOGI("播放线程退出,开始尝试恢复播放");
video_player_play(player);
}
}
else
{
LOGI("播放器线程尚未退出");
}
}