#include #include #include #include #include #include #include #include #include #include "winlib/winlib.h" #include "sound.h" #include "fplay.h" static struct decoder* init_ffmpeg_decoder(vst_t *vst) { AVCodecContext *vCtx = vst->vCtx; struct decoder *decoder; vframe_t *vframe; int i, ret; decoder = calloc(1, sizeof(struct decoder)); if(decoder == NULL) return NULL; decoder->Frame = av_frame_alloc(); if(decoder->Frame == NULL) goto err_0; decoder->nframes = 4; for(i = 0; i < decoder->nframes; i++) { vframe = &decoder->vframes[i]; ret = avpicture_alloc(&vframe->picture, vCtx->pix_fmt, vCtx->width, vCtx->height); if ( ret != 0 ) goto err_1; vframe->format = vCtx->pix_fmt; vframe->index = i; vframe->pts = 0; vframe->ready = 0; list_add_tail(&vframe->list, &vst->input_list); }; if(avcodec_open2(vCtx, vst->vCodec, NULL) < 0) { printf("Error while opening codec for input stream %d\n", vst->vStream); goto err_1; }; decoder->name = vst->vCodec->name; decoder->pix_fmt = vCtx->pix_fmt; decoder->width = vCtx->width; decoder->height = vCtx->height; decoder->codec_id = vCtx->codec_id; return decoder; err_1: for(i = i-1; i >= 0; i--) { vframe = &decoder->vframes[i]; avpicture_free(&vframe->picture); }; av_frame_free(&decoder->Frame); err_0: free(decoder); return NULL; } int init_video_decoder(vst_t *vst) { AVCodecContext *vCtx = vst->vCtx; vst->vCodec = avcodec_find_decoder(vCtx->codec_id); if(vst->vCodec == NULL) { printf("Unsupported codec with id %d for input stream %d\n", vst->vCtx->codec_id, vst->vStream); return -1; } vst->decoder = va_init_decoder(vst); if(vst->decoder == NULL) vst->decoder = init_ffmpeg_decoder(vst); if(vst->decoder != NULL) { printf("%dx%d %s %s%s decoder\n", vst->decoder->width, vst->decoder->height, av_get_pix_fmt_name(vst->decoder->pix_fmt), vst->decoder->is_hw == 0 ? "ffmpeg ":"vaapi ", vst->decoder->name); return 0; }; return -1; } void fini_video_decoder(vst_t *vst) { avcodec_close(vst->vCtx); if(vst->decoder->is_hw != 0) return; for(int i = 0; i < vst->decoder->nframes; i++) { vframe_t *vframe; vframe = &vst->decoder->vframes[i]; avpicture_free(&vframe->picture); }; av_frame_free(&vst->decoder->Frame); free(vst->decoder); }; static vframe_t *get_input_frame(vst_t *vst) { vframe_t *vframe = NULL; mutex_lock(&vst->input_lock); if(!list_empty(&vst->input_list)) { vframe = list_first_entry(&vst->input_list, vframe_t, list); list_del(&vframe->list); } mutex_unlock(&vst->input_lock); return vframe; } static void put_output_frame(vst_t *vst, vframe_t *vframe) { mutex_lock(&vst->output_lock); if(list_empty(&vst->output_list)) list_add_tail(&vframe->list, &vst->output_list); else { vframe_t *cur; cur = list_first_entry(&vst->output_list,vframe_t,list); if(vframe->pts < cur->pts) list_add_tail(&vframe->list, &vst->output_list); else { list_for_each_entry_reverse(cur,&vst->output_list,list) { if(vframe->pts > cur->pts) { list_add(&vframe->list, &cur->list); break; }; }; }; }; vst->frames_count++; mutex_unlock(&vst->output_lock); }; int decode_video(vst_t* vst) { struct decoder* decoder = vst->decoder; double pts; AVPacket pkt; int frameFinished; if(decoder->active_frame == NULL) decoder->active_frame = get_input_frame(vst); if(decoder->active_frame == NULL) return -1; if( get_packet(&vst->q_video, &pkt) == 0 ) return 0; frameFinished = 0; mutex_lock(&vst->gpu_lock); if(avcodec_decode_video2(vst->vCtx, decoder->Frame, &frameFinished, &pkt) <= 0) printf("video decoder error\n"); if(frameFinished) { vframe_t *vframe = decoder->active_frame; AVPicture *dst_pic; if(decoder->is_hw) pts = pkt.pts; else pts = av_frame_get_best_effort_timestamp(decoder->Frame); pts*= av_q2d(vst->video_time_base); dst_pic = &vframe->picture; if(vframe->is_hw_pic == 0) av_image_copy(dst_pic->data, dst_pic->linesize, (const uint8_t**)decoder->Frame->data, decoder->Frame->linesize, vst->vCtx->pix_fmt, vst->vCtx->width, vst->vCtx->height); else va_create_planar(vst, vframe); vframe->pts = pts*1000.0; vframe->pkt_pts = pkt.pts*av_q2d(vst->video_time_base)*1000.0; vframe->ready = 1; put_output_frame(vst, vframe); // printf("decoded index: %d pts: %f pkt_pts %f pkt_dts %f\n", // vst->dfx, vst->vframe[vst->dfx].pts, // vst->vframe[vst->dfx].pkt_pts, vst->vframe[vst->dfx].pkt_dts); decoder->active_frame = NULL; }; av_frame_unref(decoder->Frame); mutex_unlock(&vst->gpu_lock); av_free_packet(&pkt); return 1; }