From 1e68556c2a834bfd584070adee1aa981d8780b9a Mon Sep 17 00:00:00 2001 From: Hertz Wang Date: Mon, 29 Oct 2018 11:58:31 +0800 Subject: [PATCH 02/11] ffplay support display buffer with drm format This patch disable the video filter to support display drm buffer. If need video filter, we should duplicate a intermediate frame. Change-Id: Ic50932841c5f86e928a0c0838844eaadb4d138c0 Signed-off-by: Hertz Wang --- fftools/ffplay.c | 76 +++++++++++++++++++++++++++++++++++++++++++---- libavcodec/rkmppdec.c | 1 + libavutil/hwcontext_drm.h | 6 ++++ 3 files changed, 77 insertions(+), 6 deletions(-) diff --git a/fftools/ffplay.c b/fftools/ffplay.c index ab1f9fa..a0be207 100644 --- a/fftools/ffplay.c +++ b/fftools/ffplay.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include "libavutil/avstring.h" @@ -60,6 +61,9 @@ #include +#include +#include "libavutil/hwcontext_drm.h" + const char program_name[] = "ffplay"; const int program_birth_year = 2003; @@ -906,10 +910,46 @@ static void get_sdl_pix_fmt_and_blendmode(int format, Uint32 *sdl_pix_fmt, SDL_B } } +static void get_avframe_info(AVFrame *frame, + uint8_t *srcSlice[], + int srcStride[]) { + if (frame->format != AV_PIX_FMT_DRM_PRIME) { + memcpy(srcSlice, frame->data, sizeof(frame->data)); + memcpy(srcStride, frame->linesize, sizeof(frame->linesize)); + } else { + AVDRMFrameDescriptor *desc = (AVDRMFrameDescriptor*)frame->data[0]; + AVDRMLayerDescriptor *layer = &desc->layers[0]; + memset(srcSlice, 0, sizeof(frame->data)); + memset(srcStride, 0, sizeof(frame->linesize)); + srcSlice[0] = (uint8_t*)desc->objects[0].ptr; + srcSlice[1] = srcSlice[0] + layer->planes[1].offset; + srcStride[0] = srcStride[1] = layer->planes[0].pitch; + } +} + +static int get_avframe_format(AVFrame *frame) { + int av_format = frame->format; + if (av_format == AV_PIX_FMT_DRM_PRIME) { + AVDRMFrameDescriptor *desc = (AVDRMFrameDescriptor*)frame->data[0]; + AVDRMLayerDescriptor *layer = &desc->layers[0]; + switch (layer->format) { + case DRM_FORMAT_NV12: return AV_PIX_FMT_NV12; +#ifdef DRM_FORMAT_NV12_10 + case DRM_FORMAT_NV12_10: return AV_PIX_FMT_P010LE; +#endif + default: + av_log(NULL, AV_LOG_FATAL, "Unknown DRM Format: %d\n", + layer->format); + } + } + return av_format; +} + static int upload_texture(SDL_Texture **tex, AVFrame *frame, struct SwsContext **img_convert_ctx) { int ret = 0; Uint32 sdl_pix_fmt; SDL_BlendMode sdl_blendmode; + int av_format = get_avframe_format(frame); get_sdl_pix_fmt_and_blendmode(frame->format, &sdl_pix_fmt, &sdl_blendmode); if (realloc_texture(tex, sdl_pix_fmt == SDL_PIXELFORMAT_UNKNOWN ? SDL_PIXELFORMAT_ARGB8888 : sdl_pix_fmt, frame->width, frame->height, sdl_blendmode, 0) < 0) return -1; @@ -917,13 +957,17 @@ static int upload_texture(SDL_Texture **tex, AVFrame *frame, struct SwsContext * case SDL_PIXELFORMAT_UNKNOWN: /* This should only happen if we are not using avfilter... */ *img_convert_ctx = sws_getCachedContext(*img_convert_ctx, - frame->width, frame->height, frame->format, frame->width, frame->height, + frame->width, frame->height, av_format, frame->width, frame->height, AV_PIX_FMT_BGRA, sws_flags, NULL, NULL, NULL); if (*img_convert_ctx != NULL) { uint8_t *pixels[4]; int pitch[4]; if (!SDL_LockTexture(*tex, NULL, (void **)pixels, pitch)) { - sws_scale(*img_convert_ctx, (const uint8_t * const *)frame->data, frame->linesize, + uint8_t *srcSlice[AV_NUM_DATA_POINTERS] = { NULL }; + int srcStride[AV_NUM_DATA_POINTERS] = { 0 }; + + get_avframe_info(frame, srcSlice, srcStride); + sws_scale(*img_convert_ctx, (const uint8_t * const *)srcSlice, srcStride, 0, frame->height, pixels, pitch); SDL_UnlockTexture(*tex); } @@ -2152,6 +2196,9 @@ static int video_thread(void *arg) } for (;;) { +#if CONFIG_AVFILTER + bool support_avfilter; +#endif ret = get_video_frame(is, frame); if (ret < 0) goto the_end; @@ -2159,11 +2206,16 @@ static int video_thread(void *arg) continue; #if CONFIG_AVFILTER - if ( last_w != frame->width + // ffmpeg avfilter do not support drm fmt. + // As avfilter will modify pixels, duplicate a intermediate frame + // if wanna support avfilter for drm fmt. + support_avfilter = (frame->format != AV_PIX_FMT_DRM_PRIME); + if (support_avfilter + && (last_w != frame->width || last_h != frame->height || last_format != frame->format || last_serial != is->viddec.pkt_serial - || last_vfilter_idx != is->vfilter_idx) { + || last_vfilter_idx != is->vfilter_idx)) { av_log(NULL, AV_LOG_DEBUG, "Video frame changed from size:%dx%d format:%s serial:%d to size:%dx%d format:%s serial:%d\n", last_w, last_h, @@ -2189,11 +2241,14 @@ static int video_thread(void *arg) frame_rate = av_buffersink_get_frame_rate(filt_out); } + if (support_avfilter) { ret = av_buffersrc_add_frame(filt_in, frame); if (ret < 0) goto the_end; + } while (ret >= 0) { + if (support_avfilter) { is->frame_last_returned_time = av_gettime_relative() / 1000000.0; ret = av_buffersink_get_frame_flags(filt_out, frame, 0); @@ -2208,13 +2263,14 @@ static int video_thread(void *arg) if (fabs(is->frame_last_filter_delay) > AV_NOSYNC_THRESHOLD / 10.0) is->frame_last_filter_delay = 0; tb = av_buffersink_get_time_base(filt_out); + } #endif duration = (frame_rate.num && frame_rate.den ? av_q2d((AVRational){frame_rate.den, frame_rate.num}) : 0); pts = (frame->pts == AV_NOPTS_VALUE) ? NAN : frame->pts * av_q2d(tb); ret = queue_picture(is, frame, pts, duration, frame->pkt_pos, is->viddec.pkt_serial); av_frame_unref(frame); #if CONFIG_AVFILTER - if (is->videoq.serial != is->viddec.pkt_serial) + if (!support_avfilter || is->videoq.serial != is->viddec.pkt_serial) break; } #endif @@ -2241,8 +2297,11 @@ static int subtitle_thread(void *arg) if (!(sp = frame_queue_peek_writable(&is->subpq))) return 0; - if ((got_subtitle = decoder_decode_frame(&is->subdec, NULL, &sp->sub)) < 0) + if ((got_subtitle = decoder_decode_frame(&is->subdec, NULL, &sp->sub)) < 0) { + av_log(NULL, AV_LOG_WARNING, + "ffplay decode subtitle failed or finished\n"); break; + } pts = 0; @@ -2258,6 +2317,11 @@ static int subtitle_thread(void *arg) /* now we can update the picture count */ frame_queue_push(&is->subpq); } else if (got_subtitle) { + if (arg) { + av_log(NULL, AV_LOG_WARNING, + "ffplay only support graphics subtitle\n"); + arg = NULL; + } avsubtitle_free(&sp->sub); } } diff --git a/libavcodec/rkmppdec.c b/libavcodec/rkmppdec.c index 143d05b..b44861c 100644 --- a/libavcodec/rkmppdec.c +++ b/libavcodec/rkmppdec.c @@ -421,6 +421,7 @@ static int rkmpp_retrieve_frame(AVCodecContext *avctx, AVFrame *frame) desc->nb_objects = 1; desc->objects[0].fd = mpp_buffer_get_fd(buffer); + desc->objects[0].ptr = mpp_buffer_get_ptr(buffer); desc->objects[0].size = mpp_buffer_get_size(buffer); desc->nb_layers = 1; diff --git a/libavutil/hwcontext_drm.h b/libavutil/hwcontext_drm.h index 42709f2..4c40d15 100644 --- a/libavutil/hwcontext_drm.h +++ b/libavutil/hwcontext_drm.h @@ -50,6 +50,12 @@ typedef struct AVDRMObjectDescriptor { * DRM PRIME fd for the object. */ int fd; + + /** + * DRM PRIME mapped virtual ptr for above fd. + */ + void *ptr; + /** * Total size of the object. * -- 2.7.4