#include "play_video.h"
#include "tp_video.h"
#define MAX_QUEUE_SIZE 20
#define SMALL_WINDOW_WIDTH 144
#define SMALL_WINDOW_HEIGHT 240
typedef struct _TP_PLAYER_CONTEXT
{
VIDEO_CONTEXT video_ctx;
} TP_PLAYER_CONTEXT;
void *video_decode_thread(void *arg)
{
int ret = -1;
avdm_unit_t avdm_unit = {0};
VIDEO_STREAM video_stream = {0};
VIDEO_CONTEXT* video_ctx = (VIDEO_CONTEXT*)arg;
DECODER_HANDLER_T *decoder_handler = NULL;
if (NULL == video_ctx)
{
TP_PLAYER_ERROR("video_ctx is NULL");
return NULL;
}
decoder_handler = video_ctx->decoder_handle;
while (1)
{
if (video_ctx->video_play_end)
{
TP_PLAYER_ERROR("video play end, video docoder thread exit");
break;
}
memset(&avdm_unit, 0, sizeof(avdm_unit_t));
ret = avdm_get_next_unit(video_ctx->stream_ctx.avdm_type, &video_ctx->stream_ctx.avdm_cursor, &avdm_unit);
//TP_PLAYER_ERROR("avdm_get_next_unit ret = %d", ret);
if (ERR_NONE == ret || -ERR_OW_GET_LATEST == ret)
{
// TODO:判断第一帧是I帧, 否则丢帧
memset(&video_stream, 0, sizeof(VIDEO_STREAM));
video_stream.addr = avdm_unit.addr + sizeof(FRAME_HEAD_S); /* 需除去unit的头部 */
video_stream.stream_size = avdm_unit.len - sizeof(FRAME_HEAD_S);
video_stream.pts = avdm_unit.pts;
if (NULL == decoder_handler || NULL == decoder_handler->ops
|| NULL == decoder_handler->ops->decoder_send_stream)
{
TP_PLAYER_ERROR("decoder handle is wrong");
return NULL;
}
/* 此接口可能会阻塞 */
ret = decoder_handler->ops->decoder_send_stream(video_ctx->decoder_ctx, &video_stream);
if (OK != ret)
{
TP_PLAYER_ERROR("decoder_send_stream failed, ret = %d", ret);
}
continue;
}
else if ((-ERR_AVDM_NOT_READY == ret) || (-ERR_FRAME_NOT_READY == ret))
{
// TODO:注册回调,使用条件变量阻塞
pthread_mutex_lock(&video_ctx->stream_ctx.unit_mutex);
pthread_cond_wait(&video_ctx->stream_ctx.unit_cond, &video_ctx->stream_ctx.unit_mutex);
pthread_mutex_unlock(&video_ctx->stream_ctx.unit_mutex);
}
else
{
break;
}
}
return NULL;
}
S32 frame_receive(VIDEO_FRAME* video_frame, void* user_data)
{
VIDEO_FRAME* v_frame = NULL;
VIDEO_CONTEXT* video_ctx = NULL;
if (NULL == video_frame || NULL == user_data)
{
TP_PLAYER_ERROR("video_frame or user_data is NULL");
return ERROR;
}
video_ctx = (VIDEO_CONTEXT*)user_data;
v_frame = circular_queue_peek_writable(video_ctx->frame_queue);
if (NULL == v_frame)
{
TP_PLAYER_ERROR("ger frame from queue is NULL");
return ERROR;
}
v_frame->frame = video_frame->frame;
v_frame->height = video_frame->height;
v_frame->width = video_frame->width;
v_frame->pts = video_frame->pts;
circular_queue_push(video_ctx->frame_queue);
return OK;
}
void *video_play_thread(void *arg)
{
VIDEO_CONTEXT* video_ctx = (VIDEO_CONTEXT*)arg;
VIDEO_FRAME* v_frame = NULL;
S32 ret = ERROR;
if (NULL == video_ctx)
{
TP_PLAYER_ERROR("video_ctx is NULL");
return NULL;
}
while (1)
{
//TP_PLAYER_ERROR("video_play_thread running, queue size:%d", circular_queue_nb_remaining(video_ctx->frame_queue));
if (video_ctx->video_play_end)
{
TP_PLAYER_ERROR("video play end, video play thread exit");
break;
}
if (circular_queue_nb_remaining(video_ctx->frame_queue) > 0)
{
v_frame = circular_queue_peek(video_ctx->frame_queue);
ret = video_ctx->disp_handle->ops->disp_display_frame(v_frame);
if (ret)
{
TP_PLAYER_ERROR("disp_display ERROR: %d", ret);
}
circular_queue_move_next(video_ctx->frame_queue);
} else {
usleep(1000);
//TP_PLAYER_ERROR("video_play_thread running");
}
}
return NULL;
}
LOCAL int video_unit_cb(void *priv)
{
if (NULL == priv)
{
TP_PLAYER_ERROR("priv is NULL");
return ERROR;
}
//TP_PLAYER_ERROR("video_unit_cb in");
STREAM_CONTEXT* stream_ctx = (STREAM_CONTEXT *)priv;
pthread_mutex_lock(&stream_ctx->unit_mutex);
pthread_cond_signal(&stream_ctx->unit_cond);
pthread_mutex_unlock(&stream_ctx->unit_mutex);
return OK;
}
static int register_unit_callback(STREAM_CONTEXT* stream_ctx)
{
if (NULL == stream_ctx)
{
TP_PLAYER_ERROR("stream_ctx is NULL");
return ERROR;
}
if (ERROR == avdm_register_unit_callback(stream_ctx->avdm_type, video_unit_cb, (void *)stream_ctx))
{
TP_PLAYER_ERROR("tp_player register avdm callback failed");
return ERROR;
}
return OK;
}
static int unregister_unit_callback(STREAM_CONTEXT* stream_ctx)
{
if (NULL == stream_ctx)
{
TP_PLAYER_ERROR("stream_ctx is NULL");
return ERROR;
}
if (ERROR == avdm_unregister_unit_callback(stream_ctx->avdm_type, video_unit_cb))
{
TP_PLAYER_ERROR("tp_player unregister avdm callback failed");
return ERROR;
}
return OK;
}
static int avdm_stream_ctx_init(STREAM_CONTEXT* stream_ctx, avdm_type_t stream_type)
{
int ret = ERROR;
if (NULL == stream_ctx)
{
TP_PLAYER_ERROR("stream_ctx is NULL");
return ERROR;
}
stream_ctx->avdm_type = stream_type;
pthread_mutex_init(&stream_ctx->unit_mutex, NULL);
pthread_cond_init(&stream_ctx->unit_cond, NULL);
ret = register_unit_callback(stream_ctx);
if (OK != ret)
{
TP_PLAYER_ERROR("register unit callback failed");
pthread_mutex_destroy(&stream_ctx->unit_mutex);
pthread_cond_destroy(&stream_ctx->unit_cond);
return ERROR;
}
return OK;
}
static int avdm_stream_ctx_deinit(STREAM_CONTEXT* stream_ctx)
{
if (NULL == stream_ctx)
{
TP_PLAYER_ERROR("stream_ctx is NULL");
return ERROR;
}
unregister_unit_callback(stream_ctx);
pthread_mutex_destroy(&stream_ctx->unit_mutex);
pthread_cond_destroy(&stream_ctx->unit_cond);
return OK;
}
int release_video_frame(void* element, void* user_data)
{
VIDEO_FRAME* video_frame = NULL;
VIDEO_CONTEXT* video_ctx = NULL;
S32 ret = ERROR;
if (NULL == element || NULL == user_data)
{
TP_PLAYER_ERROR("element or user_data is NULL");
return ERROR;
}
video_frame = (VIDEO_FRAME*)element;
video_ctx = (VIDEO_CONTEXT*)user_data;
ret = video_ctx->decoder_handle->ops->decoder_release_frame(video_ctx->decoder_ctx, video_frame);
if (ret)
{
TP_PLAYER_ERROR("decoder_release_frame ERROR: %d", ret);
return ret;
}
video_frame->frame = NULL;
return ret;
}
int video_decoder_init(VIDEO_CONTEXT* video_ctx)
{
int ret = ERROR;
VIDEO_DECODE_ATTRS decoder_attrs = {
.width = 480,
.height = 800,
.decoder_type = ENCODE_TYPE_VIDEO_H264,
};
if (NULL == video_ctx)
{
TP_PLAYER_ERROR("video_ctx is NULL");
goto err_exit;
}
ret = libdecoder_init();
if (OK != ret)
{
TP_PLAYER_ERROR("libdecoder init failed");
goto err_exit;
}
video_ctx->decoder_handle = libdecoder_create_handler();
if (NULL == video_ctx->decoder_handle || NULL == video_ctx->decoder_handle->ops)
{
TP_PLAYER_ERROR("libdecoder_create_handler failed");
goto decoder_err;
}
video_ctx->decoder_ctx = video_ctx->decoder_handle->ops->decoder_init(&decoder_attrs, frame_receive, video_ctx);
if (NULL == video_ctx->decoder_ctx)
{
TP_PLAYER_ERROR("video decoder init failed");
goto decoder_err;
}
video_ctx->frame_queue = circular_queue_init(release_video_frame, video_ctx, sizeof(VIDEO_FRAME), MAX_QUEUE_SIZE);
if (NULL == video_ctx->frame_queue)
{
TP_PLAYER_ERROR("frame_queue_init failed");
goto decoder_err;
}
return OK;
decoder_err:
if (video_ctx->decoder_ctx)
{
video_ctx->decoder_handle->ops->decoder_destory(video_ctx->decoder_ctx);
video_ctx->decoder_ctx = NULL;
}
if (video_ctx->decoder_handle)
{
libdecoder_destory_handler(video_ctx->decoder_handle);
video_ctx->decoder_handle = NULL;
}
libdecoder_deinit();
err_exit:
return ERROR;
}
int video_decoder_deinit(VIDEO_CONTEXT* video_ctx)
{
if (NULL == video_ctx)
{
TP_PLAYER_ERROR("video_ctx is NULL");
return ERROR;
}
/* 销毁frame_queue时会调用解码器的接口释放帧,解码器必须在frame_queue销毁后销毁 */
circular_queue_destory(video_ctx->frame_queue);
if (video_ctx->decoder_ctx)
{
video_ctx->decoder_handle->ops->decoder_destory(video_ctx->decoder_ctx);
video_ctx->decoder_ctx = NULL;
}
if (video_ctx->decoder_handle)
{
libdecoder_destory_handler(video_ctx->decoder_handle);
video_ctx->decoder_handle = NULL;
}
libdecoder_deinit();
return ERROR;
}
int display_init(VIDEO_CONTEXT* video_ctx)
{
int ret = ERROR;
if (NULL == video_ctx)
{
TP_PLAYER_ERROR("video_ctx is NULL");
return ERROR;
}
/* 视频通话时, cap的screen模块已经调用libdisp_init(),此处无需调用,或者libdisp_init中增加引用计数,若没有实现引用计数,不可调用libdisp_deinit*/
video_ctx->disp_handle = libdisp_create_handler();
if (NULL == video_ctx->disp_handle || NULL == video_ctx->disp_handle->ops)
{
TP_PLAYER_ERROR("libdisp_create_handler failed");
return ERROR;
}
ret = video_ctx->disp_handle->ops->disp_set_type(PIP_WIN_DISP_LOCAL_VIDEO_TYPE);
if (ret)
{
TP_PLAYER_ERROR("tp_player_init ERROR: %d", ret);
libdisp_destory_handler(video_ctx->disp_handle);
video_ctx->disp_handle = NULL;
return ERROR;
}
return OK;
}
int display_deinit(VIDEO_CONTEXT* video_ctx)
{
if (NULL == video_ctx)
{
TP_PLAYER_ERROR("video_ctx is NULL");
return ERROR;
}
/* TODO:设置屏幕显示模式? */
libdisp_destory_handler(video_ctx->disp_handle);
video_ctx->disp_handle = NULL;
return OK;
}
int video_pip_stream_start(VIDEO_CONTEXT* video_ctx)
{
int ret = ERROR;
if (NULL == video_ctx)
{
TP_PLAYER_ERROR("video_ctx is NULL");
return ERROR;
}
if (video_ctx->avdc_handler && video_ctx->avdc_handler->ops)
{
ret = video_ctx->avdc_handler->ops->video_stream_start(video_ctx->avdc_handler);
if (ret)
{
TP_PLAYER_ERROR("start local stream failed");
return ERROR;
}
}
video_ctx->is_local_stream_open = TRUE;
return OK;
}
int video_pip_stream_stop(VIDEO_CONTEXT* video_ctx)
{
int ret = ERROR;
if (NULL == video_ctx)
{
TP_PLAYER_ERROR("video_ctx is NULL");
return ERROR;
}
if (video_ctx->avdc_handler && video_ctx->avdc_handler->ops)
{
ret = video_ctx->avdc_handler->ops->video_stream_stop(video_ctx->avdc_handler);
if (ret)
{
TP_PLAYER_ERROR("stop local stream failed");
return ERROR;
}
}
video_ctx->is_local_stream_open = FALSE;
return OK;
}
static int video_pip_stream_init(VIDEO_CONTEXT* video_ctx)
{
int ret = ERROR;
TP_STREAM_ATTR_S video_attr = {
.strm_id = STRM_ID_SCREEN_DISP,
.framerate = {
.low = 20,
.high = 1,
},
.strm_res = {
.res_w = SMALL_WINDOW_WIDTH,
.res_h = SMALL_WINDOW_HEIGHT,
},
.strm_max_res = {
.res_w = 480,
.res_h = 800,
}
};
if (NULL == video_ctx)
{
TP_PLAYER_ERROR("video_ctx is NULL");
return ERROR;
}
video_ctx->avdc_handler = avdc_create_video_handler(&video_attr);
if (NULL == video_ctx->avdc_handler || NULL == video_ctx->avdc_handler->ops)
{
TP_PLAYER_ERROR("avdc_create_video_handler failed");
return ERROR;
}
ret = video_pip_stream_start(video_ctx);
if (ret)
{
TP_PLAYER_ERROR("start local stream failed");
avdc_destory_handler(video_ctx->avdc_handler);
video_ctx->avdc_handler = NULL;
return ERROR;
}
return OK;
}
static int vidoe_pip_stream_deinit(VIDEO_CONTEXT* video_ctx)
{
int ret = ERROR;
if (NULL == video_ctx)
{
TP_PLAYER_ERROR("video_ctx is NULL");
return ERROR;
}
ret = video_pip_stream_stop(video_ctx);
if (ret)
{
TP_PLAYER_ERROR("stop local stream failed");
return ERROR;
}
if (video_ctx->avdc_handler)
{
avdc_destory_handler(video_ctx->avdc_handler);
video_ctx->avdc_handler = NULL;
}
return OK;
}
int create_video_decode_thread(VIDEO_CONTEXT* video_ctx)
{
int ret = ERROR;
if (NULL == video_ctx)
{
TP_PLAYER_ERROR("video_ctx is NULL");
return ERROR;
}
ret = avdm_stream_ctx_init(&video_ctx->stream_ctx, AVDM_TYPE_VIDEO_CALL);
if (OK != ret)
{
TP_PLAYER_ERROR("register unit callback failed");
return ret;
}
ret = video_decoder_init(video_ctx);
if (OK != ret)
{
TP_PLAYER_ERROR("decoder init failed");
avdm_stream_ctx_deinit(&video_ctx->stream_ctx);
return ret;
}
if (0 != pthread_create(&video_ctx->decoder_pid, NULL, video_decode_thread, video_ctx))
{
TP_PLAYER_ERROR("pthread_create video_decode_thread failed");
video_decoder_deinit(video_ctx);
avdm_stream_ctx_deinit(&video_ctx->stream_ctx);
return ERROR;
}
return OK;
}
int create_video_display_thread(VIDEO_CONTEXT* video_ctx)
{
int ret = ERROR;
if (NULL == video_ctx)
{
TP_PLAYER_ERROR("video_ctx is NULL");
return ERROR;
}
ret = display_init(video_ctx);
if (OK != ret)
{
TP_PLAYER_ERROR("frame display init failed");
return ERROR;
}
if (0 != pthread_create(&video_ctx->play_pid, NULL, video_play_thread, video_ctx))
{
TP_PLAYER_ERROR("pthread_create video_play_thread failed");
display_deinit(video_ctx);
return ERROR;
}
return OK;
}
int video_play_init(VIDEO_CONTEXT* video_ctx)
{
int ret = ERROR;
if (NULL == video_ctx)
{
TP_PLAYER_ERROR("video_ctx is NULL");
return ERROR;
}
video_ctx->video_play_end = FALSE;
ret = create_video_decode_thread(video_ctx);
if (OK != ret)
{
TP_PLAYER_ERROR("video decoder init failed");
return ERROR;
}
ret = create_video_display_thread(video_ctx);
if (OK != ret)
{
TP_PLAYER_ERROR("video decoder init failed");
video_ctx->video_play_end = TRUE;
pthread_join(video_ctx->decoder_pid, NULL);
video_decoder_deinit(video_ctx);
avdm_stream_ctx_deinit(&video_ctx->stream_ctx);
return ERROR;
}
/* 初始化用于画中画的本地视频流 */
ret = video_pip_stream_init(video_ctx);
if (ret)
{
TP_PLAYER_ERROR("pip stream init failed");
video_ctx->video_play_end = TRUE;
pthread_join(video_ctx->decoder_pid, NULL);
pthread_join(video_ctx->play_pid, NULL);
/* 解码线程和播放线程都用到了用于缓存解码帧的队列,必须等两个线程都退出后再销毁解码器相关资源 */
video_decoder_deinit(video_ctx);
avdm_stream_ctx_deinit(&video_ctx->stream_ctx);
display_deinit(video_ctx);
return ERROR;
}
return OK;
}
int video_play_deinit(VIDEO_CONTEXT* video_ctx)
{
if (NULL == video_ctx)
{
TP_PLAYER_ERROR("video_ctx is NULL");
return ERROR;
}
video_ctx->video_play_end = TRUE;
vidoe_pip_stream_deinit(video_ctx);
pthread_join(video_ctx->decoder_pid, NULL);
pthread_join(video_ctx->play_pid, NULL);
/* 解码线程和播放线程都用到了用于缓存解码帧的队列,必须等两个线程都退出后再销毁解码器和队列 */
video_decoder_deinit(video_ctx);
avdm_stream_ctx_deinit(&video_ctx->stream_ctx);
display_deinit(video_ctx);
return OK;
}解释代码