diff --git a/contrib/media/fplay/fplay.c b/contrib/media/fplay/fplay.c index c5656832ec..813991249b 100644 --- a/contrib/media/fplay/fplay.c +++ b/contrib/media/fplay/fplay.c @@ -16,26 +16,17 @@ #include "sound.h" #include "fplay.h" -#ifdef HAVE_VAAPI -int va_check_codec_support(enum AVCodecID id); -#endif - volatile enum player_state player_state = STOP; volatile enum player_state decoder_state = PREPARE; volatile enum player_state sound_state = STOP; uint32_t win_width, win_height; -int have_sound = 0; +int have_sound = 0; uint8_t *decoder_buffer; extern int resampler_size; - extern int sample_rate; -char *movie_file; - -void flush_video(vst_t* vst); - int64_t rewind_pos; @@ -46,12 +37,6 @@ int threads_running = DECODER_THREAD; extern double audio_base; -double get_audio_base(vst_t* vst) -{ - return (double)av_q2d(vst->fCtx->streams[vst->aStream]->time_base)*1000; -}; - - int main( int argc, char *argv[]) { static vst_t vst; @@ -60,14 +45,14 @@ int main( int argc, char *argv[]) if(argc < 2) { - movie_file = get_moviefile(); - if(movie_file == NULL) + vst.input_file = get_moviefile(); + if(vst.input_file == NULL) { printf("Please provide a movie file\n"); return -1; } } - else movie_file = argv[1]; + else vst.input_file = argv[1]; /* register all codecs, demux and protocols */ @@ -77,9 +62,9 @@ int main( int argc, char *argv[]) avdevice_register_all(); av_register_all(); - if( avformat_open_input(&vst.fCtx, movie_file, NULL, NULL) < 0) + if( avformat_open_input(&vst.fCtx, vst.input_file, NULL, NULL) < 0) { - printf("Cannot open file %s\n\r", movie_file); + printf("Cannot open file %s\n\r", vst.input_file); return -1; // Couldn't open file }; @@ -92,15 +77,15 @@ int main( int argc, char *argv[]) return -1; }; - file_name = strrchr(movie_file,'/')+1; + file_name = strrchr(vst.input_file,'/')+1; dot = strrchr(file_name,'.'); if(dot) { - movie_file = malloc(dot-file_name+1); - memcpy(movie_file, file_name, dot-file_name); - movie_file[dot-file_name] = 0; + vst.input_name = malloc(dot-file_name+1); + memcpy(vst.input_name, file_name, dot-file_name); + vst.input_name[dot-file_name] = 0; } - else movie_file = file_name; + else vst.input_name = file_name; stream_duration = vst.fCtx->duration; @@ -114,7 +99,7 @@ int main( int argc, char *argv[]) && vst.vStream < 0) { vst.vStream = i; - video_time_base = vst.fCtx->streams[i]->time_base; + vst.video_time_base = vst.fCtx->streams[i]->time_base; if(stream_duration == 0) stream_duration = vst.fCtx->streams[i]->duration; } @@ -123,6 +108,7 @@ int main( int argc, char *argv[]) vst.aStream < 0) { vst.aStream = i; + vst.audio_time_base = vst.fCtx->streams[i]->time_base; if(stream_duration == 0) stream_duration = vst.fCtx->streams[i]->duration; } @@ -141,8 +127,6 @@ int main( int argc, char *argv[]) vst.aCtx = vst.fCtx->streams[vst.aStream]->codec; vst.vCodec = avcodec_find_decoder(vst.vCtx->codec_id); - printf("codec id %x name %s\n",vst.vCtx->codec_id, vst.vCodec->name); - printf("ctx->pix_fmt %d\n", vst.vCtx->pix_fmt); INIT_LIST_HEAD(&vst.input_list); INIT_LIST_HEAD(&vst.output_list); @@ -157,9 +141,16 @@ int main( int argc, char *argv[]) { printf("Unsupported codec with id %d for input stream %d\n", vst.vCtx->codec_id, vst.vStream); - return -1; // Codec not found + return -1; } + vst.Frame = av_frame_alloc(); + if(vst.Frame == NULL) + { + printf("Cannot alloc video frame\n"); + return -1; + }; + if(fplay_init_context(&vst)) return -1; @@ -170,8 +161,6 @@ int main( int argc, char *argv[]) return -1; // Could not open codec }; - printf("ctx->pix_fmt %d\n", vst.vCtx->pix_fmt); - if (vst.aCtx->channels > 0) vst.aCtx->request_channels = FFMIN(2, vst.aCtx->channels); else @@ -223,10 +212,10 @@ int main( int argc, char *argv[]) } else printf("Unsupported audio codec!\n"); - if(!init_video(&vst)) - return 0; - - mutex_lock_timeout(&vst.decoder_lock, 3000); + mutex_lock(&vst.decoder_lock); + create_thread(video_thread, &vst, 1024*1024); + if(mutex_lock_timeout(&vst.decoder_lock, 3000) == 0) + return -1; decoder(&vst); @@ -369,7 +358,6 @@ void decoder(vst_t* vst) delay(1); continue; } - yield(); continue; diff --git a/contrib/media/fplay/fplay.h b/contrib/media/fplay/fplay.h index f1aa7e6556..40e2455f41 100644 --- a/contrib/media/fplay/fplay.h +++ b/contrib/media/fplay/fplay.h @@ -27,7 +27,6 @@ typedef struct int index; double pts; double pkt_pts; - double pkt_dts; volatile int ready; }vframe_t; @@ -111,21 +110,24 @@ typedef struct { int put_packet(queue_t *q, AVPacket *pkt); int get_packet(queue_t *q, AVPacket *pkt); -#define HWDEC_NUM_SURFACES 16 struct vstate { - AVFormatContext *fCtx; /* format context */ - AVCodecContext *vCtx; /* video decoder context */ - AVCodecContext *aCtx; /* audio decoder context */ - AVCodec *vCodec; /* video codec */ - AVCodec *aCodec; /* audio codec */ - int vStream; /* video stream index */ - int aStream; /* audio stream index */ + AVFormatContext *fCtx; /* format context */ + AVCodecContext *vCtx; /* video decoder context */ + AVCodecContext *aCtx; /* audio decoder context */ + AVCodec *vCodec; /* video codec */ + AVCodec *aCodec; /* audio codec */ + char *input_file; + char *input_name; + int vStream; /* video stream index */ + int aStream; /* audio stream index */ + AVRational video_time_base; + AVRational audio_time_base; - queue_t q_video; /* video packets queue */ - queue_t q_audio; /* audio packets queue */ + queue_t q_video; /* video packets queue */ + queue_t q_audio; /* audio packets queue */ - mutex_t gpu_lock; /* gpu access lock. libdrm not yet thread safe :( */ + mutex_t gpu_lock; /* gpu access lock. libdrm not yet thread safe :( */ mutex_t decoder_lock; mutex_t input_lock; @@ -133,13 +135,18 @@ struct vstate struct list_head input_list; struct list_head output_list; + AVFrame *Frame; + vframe_t *decoder_frame; - void *hwCtx; /* hardware context */ - int hwdec:1; /* hardware decoder */ - int blit_bitmap:1; /* hardware RGBA blitter */ - int blit_texture:1; /* hardware RGBA blit and scale */ - int blit_planar:1; /* hardbare YUV blit and scale */ + volatile int frames_count; + void *hwCtx; /* hardware context */ + int hwdec:1; /* hardware decoder */ + int blit_bitmap:1; /* hardware RGBA blitter */ + int blit_texture:1; /* hardware RGBA blit and scale */ + int blit_planar:1; /* hardbare YUV blit and scale */ int frame_reorder:1; + int nframes; + vframe_t vframes[16]; }; @@ -149,7 +156,6 @@ struct vstate extern int threads_running; extern astream_t astream; -extern AVRational video_time_base; render_t *create_render(vst_t *vst, window_t *win, uint32_t flags); void destroy_render(render_t *render); @@ -164,8 +170,8 @@ int init_audio(int format); int audio_thread(void *param); void set_audio_volume(int left, int right); -int init_video(vst_t* vst); int video_thread(void *param); +void flush_video(vst_t* vst); void decoder(vst_t *vst); int decode_video(vst_t* vst); @@ -180,6 +186,11 @@ static inline void GetNotify(void *event) ::"a"(68),"b"(14),"c"(event)); } +static inline double get_audio_base(vst_t* vst) +{ + return (double)av_q2d(vst->fCtx->streams[vst->aStream]->time_base)*1000; +}; + void va_create_planar(vst_t *vst, vframe_t *vframe); int init_fontlib(); diff --git a/contrib/media/fplay/vaapi.c b/contrib/media/fplay/vaapi.c index 7b5541d68b..7b3287f8f8 100644 --- a/contrib/media/fplay/vaapi.c +++ b/contrib/media/fplay/vaapi.c @@ -39,7 +39,7 @@ struct hw_profile static int drm_fd = 0; static struct vaapi_context *v_context; -static VASurfaceID v_surface_id[HWDEC_NUM_SURFACES]; +static VASurfaceID v_surface_id[16]; #define HAS_HEVC VA_CHECK_VERSION(0, 38, 0) #define HAS_VP9 (VA_CHECK_VERSION(0, 38, 1) && defined(FF_PROFILE_VP9_0)) @@ -281,10 +281,10 @@ static int has_entrypoint(struct vaapi_context *vaapi, VAProfile profile, VAEntr return 0; } -static int vaapi_init_decoder(VAProfile profile, - VAEntrypoint entrypoint, - unsigned int picture_width, - unsigned int picture_height) +static int vaapi_init_decoder(vst_t *vst,VAProfile profile, + VAEntrypoint entrypoint, + unsigned int picture_width, + unsigned int picture_height) { struct vaapi_context* const vaapi = v_context; VAConfigAttrib attrib; @@ -343,7 +343,7 @@ ENTER(); printf("vaCreateSurfaces %dx%d\n",picture_width,picture_height); status = vaCreateSurfaces(vaapi->display, VA_RT_FORMAT_YUV420, picture_width, picture_height, - v_surface_id,HWDEC_NUM_SURFACES,NULL,0); + v_surface_id,vst->nframes,NULL,0); if (!vaapi_check_status(status, "vaCreateSurfaces()")) { FAIL(); @@ -378,7 +378,7 @@ ENTER(); status = vaCreateContext(vaapi->display, config_id, picture_width, picture_height, VA_PROGRESSIVE, - v_surface_id, HWDEC_NUM_SURFACES, + v_surface_id, vst->nframes, &context_id); if (!vaapi_check_status(status, "vaCreateContext()")) { @@ -396,9 +396,9 @@ ENTER(); static enum PixelFormat get_format(struct AVCodecContext *avctx, const enum AVPixelFormat *fmt) { + vst_t *vst = (vst_t*)avctx->opaque; VAProfile profile = VAProfileNone; - ENTER(); for (int i = 0; fmt[i] != PIX_FMT_NONE; i++) { @@ -419,17 +419,15 @@ static enum PixelFormat get_format(struct AVCodecContext *avctx, hw_profiles[n].ff_profile == avctx->profile) { profile = hw_profiles[n].va_profile; - if (vaapi_init_decoder(profile, VAEntrypointVLD, avctx->width, avctx->height) == 0) + if (vaapi_init_decoder(vst, profile, VAEntrypointVLD, avctx->width, avctx->height) == 0) { avctx->hwaccel_context = v_context; - LEAVE(); return fmt[i]; ; } } } } - FAIL(); return PIX_FMT_NONE; } @@ -472,6 +470,8 @@ int fplay_init_context(vst_t *vst) { AVCodecContext *vCtx = vst->vCtx; + vst->nframes = 4; + if(va_check_codec_support(vCtx->codec_id)) { VADisplay dpy; @@ -481,9 +481,12 @@ int fplay_init_context(vst_t *vst) if(vst->hwCtx != NULL) { - for(int i = 0; i < HWDEC_NUM_SURFACES; i++) + if(vCtx->codec_id == AV_CODEC_ID_H264) + vst->nframes = 16; + + for(int i = 0; i < vst->nframes; i++) { - vframe_t *vframe = calloc(1, sizeof(*vframe)); + vframe_t *vframe = &vst->vframes[i]; vframe->format = AV_PIX_FMT_NONE; vframe->is_hw_pic = 1; @@ -494,6 +497,7 @@ int fplay_init_context(vst_t *vst) }; vst->hwdec = 1; + vst->frame_reorder = 1; vCtx->opaque = vst; vCtx->thread_count = 1; vCtx->get_format = get_format; @@ -504,12 +508,12 @@ int fplay_init_context(vst_t *vst) vst->hwdec = 0; - for(int i = 0; i < HWDEC_NUM_SURFACES; i++) + for(int i = 0; i < vst->nframes; i++) { vframe_t *vframe; int ret; - vframe = calloc(1, sizeof(*vframe)); + vframe = &vst->vframes[i]; ret = avpicture_alloc(&vframe->picture, vst->vCtx->pix_fmt, vst->vCtx->width, vst->vCtx->height); diff --git a/contrib/media/fplay/video.c b/contrib/media/fplay/video.c index 09308a76f0..5978bd7987 100644 --- a/contrib/media/fplay/video.c +++ b/contrib/media/fplay/video.c @@ -21,16 +21,10 @@ extern int64_t stream_duration; extern volatile int sound_level_0; extern volatile int sound_level_1; -volatile int frames_count = 0; - struct SwsContext *cvt_ctx = NULL; - render_t *main_render; -AVRational video_time_base; -AVFrame *Frame; - void get_client_rect(rect_t *rc); void run_render(window_t *win, void *render); void window_update_layout(window_t *win); @@ -51,30 +45,12 @@ void flush_video(vst_t *vst) vframe->pts = 0; vframe->ready = 0; } + vst->frames_count = 0; mutex_unlock(&vst->input_lock); mutex_unlock(&vst->output_lock); - - frames_count = 0; }; -int init_video(vst_t *vst) -{ - Frame = av_frame_alloc(); - if ( Frame == NULL ) - { - printf("Cannot alloc video frame\n\r"); - return 0; - }; - - mutex_lock(&vst->decoder_lock); - - create_thread(video_thread, vst, 1024*1024); - - return 1; -}; - -static double dts = 0.0; static vframe_t *get_input_frame(vst_t *vst) { @@ -115,31 +91,31 @@ static void put_output_frame(vst_t *vst, vframe_t *vframe) }; }; }; + vst->frames_count++; mutex_unlock(&vst->output_lock); }; int decode_video(vst_t* vst) { - AVPacket pkt; double pts; + AVPacket pkt; + int frameFinished; if(vst->decoder_frame == NULL) vst->decoder_frame = get_input_frame(vst); if(vst->decoder_frame == NULL) - return 0; + return -1; if( get_packet(&vst->q_video, &pkt) == 0 ) return 0; frameFinished = 0; - if(dts == 0) - dts = pkt.pts; mutex_lock(&vst->gpu_lock); - if(avcodec_decode_video2(vst->vCtx, Frame, &frameFinished, &pkt) <= 0) + if(avcodec_decode_video2(vst->vCtx, vst->Frame, &frameFinished, &pkt) <= 0) printf("video decoder error\n"); if(frameFinished) @@ -150,22 +126,21 @@ int decode_video(vst_t* vst) if(vst->hwdec) pts = pkt.pts; else - pts = av_frame_get_best_effort_timestamp(Frame); + pts = av_frame_get_best_effort_timestamp(vst->Frame); - pts*= av_q2d(video_time_base); + 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**)Frame->data, - Frame->linesize, vst->vCtx->pix_fmt, vst->vCtx->width, vst->vCtx->height); + (const uint8_t**)vst->Frame->data, + vst->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(video_time_base)*1000.0; - vframe->pkt_dts = dts*av_q2d(video_time_base)*1000.0; + vframe->pkt_pts = pkt.pts*av_q2d(vst->video_time_base)*1000.0; vframe->ready = 1; put_output_frame(vst, vframe); @@ -175,10 +150,8 @@ int decode_video(vst_t* vst) // vst->vframe[vst->dfx].pkt_pts, vst->vframe[vst->dfx].pkt_dts); vst->decoder_frame = NULL; - frames_count++; - dts = 0; }; - av_frame_unref(Frame); + av_frame_unref(vst->Frame); mutex_unlock(&vst->gpu_lock); av_free_packet(&pkt); @@ -417,7 +390,7 @@ void render_time(render_t *render) delay(1); return; } - else if (decoder_state == STOP && frames_count == 0 && + else if (decoder_state == STOP && vst->frames_count == 0 && player_state != STOP) { player_stop(); @@ -441,10 +414,11 @@ void render_time(render_t *render) vframe = list_first_entry(&vst->output_list, vframe_t, list); list_del(&vframe->list); + vst->frames_count--; mutex_unlock(&vst->output_lock); ctime = get_master_clock(); - fdelay = (vframe->pkt_pts - ctime); + fdelay = (vframe->pts - ctime); if(fdelay > 15.0) { @@ -458,7 +432,7 @@ void render_time(render_t *render) if(main_render->win->win_state != FULLSCREEN) { - prg->current = vframe->pkt_pts * 1000; + prg->current = vframe->pts * 1000; lvl->current = vframe->index & 1 ? sound_level_1 : sound_level_0; send_message(&prg->ctrl, PRG_PROGRESS, 0, 0); @@ -467,7 +441,6 @@ void render_time(render_t *render) send_message(&lvl->ctrl, MSG_PAINT, 0, 0); } - frames_count--; vframe->ready = 0; mutex_lock(&vst->input_lock); @@ -476,9 +449,6 @@ void render_time(render_t *render) } } - -extern char *movie_file; - int video_thread(void *param) { vst_t *vst = param; @@ -486,7 +456,7 @@ int video_thread(void *param) init_winlib(); - MainWindow = create_window(movie_file,0, + MainWindow = create_window(vst->input_name,0, 10,10,vst->vCtx->width,vst->vCtx->height+CAPTION_HEIGHT+PANEL_HEIGHT,MainWindowProc); MainWindow->panel.prg->max = stream_duration;