From 7218b51863e89afcbcf8083285bddffeea4f17ce Mon Sep 17 00:00:00 2001 From: "Sergey Semyonov (Serge)" Date: Mon, 1 Feb 2016 15:10:02 +0000 Subject: [PATCH] Fplay: ffmpeg-2.5 compatible edition git-svn-id: svn://kolibrios.org@6117 a494cfbc-eb01-0410-851d-a64ba20cac60 --- contrib/media/fplay/Makefile | 2 +- contrib/media/fplay/audio.c | 4 +- contrib/media/fplay/fplay.c | 194 ++++++----- contrib/media/fplay/fplay.h | 32 +- contrib/media/fplay/vaapi.c | 612 +++++++++++++++++++++++++++++++++++ contrib/media/fplay/video.c | 54 ++-- 6 files changed, 759 insertions(+), 139 deletions(-) create mode 100644 contrib/media/fplay/vaapi.c diff --git a/contrib/media/fplay/Makefile b/contrib/media/fplay/Makefile index 4849da0e0b..c3d2509f14 100644 --- a/contrib/media/fplay/Makefile +++ b/contrib/media/fplay/Makefile @@ -19,7 +19,7 @@ INCLUDES+=-I$(SDK_DIR)/sources/freetype/include #-I$(SDK_DIR)/sources/vaapi/libva-1.4.1 #DEFINES= -DDEBUG=1 -DPACKAGE_NAME=\"Fplay-vaapi\" -LIBS:= -lsync -lavdevice.dll -lavformat.dll -lavcodec.dll -lavutil.dll -lswscale.dll +LIBS:= -lavdevice.dll -lavformat.dll -lavcodec.dll -lavutil.dll -lswscale.dll LIBS+= -lswresample.dll -lsound -lpixlib3 -lfreetype.dll -lva.dll -lgcc -lc.dll -lapp LIBPATH:= -L$(LIB_DIR) -L/home/autobuild/tools/win32/mingw32/lib diff --git a/contrib/media/fplay/audio.c b/contrib/media/fplay/audio.c index a2b0781db6..abe399a886 100644 --- a/contrib/media/fplay/audio.c +++ b/contrib/media/fplay/audio.c @@ -23,8 +23,6 @@ volatile enum player_state player_state; volatile enum player_state decoder_state; volatile enum player_state sound_state; -extern mutex_t driver_lock; - static SNDBUF hBuff; static int snd_format; @@ -108,7 +106,7 @@ int decode_audio(AVCodecContext *ctx, queue_t *qa) if (!aFrame) { - if (!(aFrame = avcodec_alloc_frame())) + if (!(aFrame = av_frame_alloc())) return -1; } else avcodec_get_frame_defaults(aFrame); diff --git a/contrib/media/fplay/fplay.c b/contrib/media/fplay/fplay.c index ace44ef3e8..0dc7038088 100644 --- a/contrib/media/fplay/fplay.c +++ b/contrib/media/fplay/fplay.c @@ -25,14 +25,7 @@ uint32_t win_width, win_height; void decoder(); int fplay_init_context(AVCodecContext *avctx); -AVFormatContext *pFormatCtx; -AVCodecContext *pCodecCtx; -AVCodecContext *aCodecCtx; -AVCodec *pCodec; -AVCodec *aCodec; AVFrame *pFrame; -int videoStream; -int audioStream; int have_sound = 0; @@ -44,8 +37,7 @@ char *movie_file; void flush_video(); -queue_t q_video; -queue_t q_audio; + int64_t rewind_pos; int64_t stream_duration; @@ -54,15 +46,17 @@ int threads_running = DECODER_THREAD; extern double audio_base; -double get_audio_base() + +double get_audio_base(vst_t* vst) { - return (double)av_q2d(pFormatCtx->streams[audioStream]->time_base)*1000; + return (double)av_q2d(vst->fCtx->streams[vst->aStream]->time_base)*1000; }; int main( int argc, char *argv[]) { - int i; + static vst_t vst; + int i, ret; char *file_name, *dot; if(argc < 2) @@ -84,16 +78,16 @@ int main( int argc, char *argv[]) avdevice_register_all(); av_register_all(); - if( avformat_open_input(&pFormatCtx, movie_file, NULL, NULL) < 0) + if( avformat_open_input(&vst.fCtx, movie_file, NULL, NULL) < 0) { printf("Cannot open file %s\n\r", movie_file); return -1; // Couldn't open file }; - pFormatCtx->flags |= AVFMT_FLAG_GENPTS; + vst.fCtx->flags |= AVFMT_FLAG_GENPTS; // Retrieve stream information - if(avformat_find_stream_info(pFormatCtx, NULL)<0) + if(avformat_find_stream_info(vst.fCtx, NULL) < 0) { printf("Cannot find streams\n\r"); return -1; @@ -109,32 +103,33 @@ int main( int argc, char *argv[]) } else movie_file = file_name; - stream_duration = pFormatCtx->duration; + stream_duration = vst.fCtx->duration; // Find the first video stream - videoStream=-1; - audioStream=-1; - for(i=0; i < pFormatCtx->nb_streams; i++) - { - if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_VIDEO - && videoStream < 0) - { - videoStream=i; - video_time_base = pFormatCtx->streams[i]->time_base; - if(stream_duration == 0) - stream_duration = pFormatCtx->streams[i]->duration; + vst.vStream = -1; + vst.aStream = -1; - } - if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_AUDIO && - audioStream < 0) + for(i=0; i < vst.fCtx->nb_streams; i++) + { + if(vst.fCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_VIDEO + && vst.vStream < 0) { - audioStream=i; + vst.vStream = i; + video_time_base = vst.fCtx->streams[i]->time_base; if(stream_duration == 0) - stream_duration = pFormatCtx->streams[i]->duration; + stream_duration = vst.fCtx->streams[i]->duration; + } + + if(vst.fCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_AUDIO && + vst.aStream < 0) + { + vst.aStream = i; + if(stream_duration == 0) + stream_duration = vst.fCtx->streams[i]->duration; } } - if(videoStream==-1) + if(vst.vStream==-1) { printf("Video stream not detected\n\r"); return -1; // Didn't find a video stream @@ -143,59 +138,60 @@ int main( int argc, char *argv[]) // __asm__ __volatile__("int3"); // Get a pointer to the codec context for the video stream - pCodecCtx = pFormatCtx->streams[videoStream]->codec; - aCodecCtx = pFormatCtx->streams[audioStream]->codec; + vst.vCtx = vst.fCtx->streams[vst.vStream]->codec; + vst.aCtx = vst.fCtx->streams[vst.aStream]->codec; - // Find the decoder for the video stream + 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); - - pCodec=avcodec_find_decoder(pCodecCtx->codec_id); - -// printf("ctx->pix_fmt %d\n", pCodecCtx->pix_fmt); - - if(pCodec==NULL) { + if(vst.vCodec == NULL) + { printf("Unsupported codec with id %d for input stream %d\n", - pCodecCtx->codec_id, videoStream); + vst.vCtx->codec_id, vst.vStream); return -1; // Codec not found } - if(avcodec_open2(pCodecCtx, pCodec, NULL) < 0) + + + + if(avcodec_open2(vst.vCtx, vst.vCodec, NULL) < 0) { printf("Error while opening codec for input stream %d\n", - videoStream); + vst.vStream); return -1; // Could not open codec }; -// printf("ctx->pix_fmt %d\n", pCodecCtx->pix_fmt); - mutex_init(&q_video.lock); - mutex_init(&q_audio.lock); + mutex_init(&vst.q_video.lock); + mutex_init(&vst.q_audio.lock); + mutex_init(&vst.gpu_lock); - if (aCodecCtx->channels > 0) - aCodecCtx->request_channels = FFMIN(2, aCodecCtx->channels); + if (vst.aCtx->channels > 0) + vst.aCtx->request_channels = FFMIN(2, vst.aCtx->channels); else - aCodecCtx->request_channels = 2; + vst.aCtx->request_channels = 2; - aCodec = avcodec_find_decoder(aCodecCtx->codec_id); + vst.aCodec = avcodec_find_decoder(vst.aCtx->codec_id); - if(aCodec) + if(vst.aCodec) { - if(avcodec_open2(aCodecCtx, aCodec, NULL) >= 0 ) + if(avcodec_open2(vst.aCtx, vst.aCodec, NULL) >= 0 ) { WAVEHEADER whdr; int fmt; int channels; printf("audio stream rate %d channels %d format %d\n", - aCodecCtx->sample_rate, aCodecCtx->channels, aCodecCtx->sample_fmt ); + vst.aCtx->sample_rate, vst.aCtx->channels, vst.aCtx->sample_fmt ); whdr.riff_id = 0x46464952; whdr.riff_format = 0x45564157; whdr.wFormatTag = 0x01; - whdr.nSamplesPerSec = aCodecCtx->sample_rate; + whdr.nSamplesPerSec = vst.aCtx->sample_rate; whdr.nChannels = 2; whdr.wBitsPerSample = 16; - sample_rate = aCodecCtx->sample_rate; + sample_rate = vst.aCtx->sample_rate; fmt = test_wav(&whdr); @@ -222,10 +218,10 @@ int main( int argc, char *argv[]) } else printf("Unsupported audio codec!\n"); - if( !init_video(pCodecCtx)) + if(!init_video(&vst)) return 0; - decoder(); + decoder(&vst); // Free the YUV frame av_free(pFrame); @@ -240,31 +236,31 @@ int main( int argc, char *argv[]) if(astream.lock.handle) mutex_destroy(&astream.lock); - mutex_destroy(&q_video.lock); - mutex_destroy(&q_audio.lock); + mutex_destroy(&vst.q_video.lock); + mutex_destroy(&vst.q_audio.lock); return 0; } -static int load_frame() +static int load_frame(vst_t *vst) { AVPacket packet; int err; - err = av_read_frame(pFormatCtx, &packet); + err = av_read_frame(vst->fCtx, &packet); if( err == 0) { - if(packet.stream_index==videoStream) - put_packet(&q_video, &packet); - else if( (packet.stream_index == audioStream) && + if(packet.stream_index == vst->vStream) + put_packet(&vst->q_video, &packet); + else if( (packet.stream_index == vst->aStream) && (have_sound != 0) ) { - put_packet(&q_audio, &packet); + put_packet(&vst->q_audio, &packet); if(audio_base == -1.0) { if (packet.pts != AV_NOPTS_VALUE) - audio_base = get_audio_base() * packet.pts; + audio_base = get_audio_base(vst) * packet.pts; // printf("audio base %f\n", audio_base); }; } @@ -278,30 +274,28 @@ static int load_frame() -static int fill_queue() +static int fill_queue(vst_t* vst) { int err = 0; AVPacket packet; - while( (q_video.size < 4*1024*1024) && - !err ) - err = load_frame(); + while( (vst->q_video.size < 4*1024*1024) && !err ) + err = load_frame(vst); return err; - }; -static void flush_all() +static void flush_all(vst_t* vst) { AVPacket packet; - avcodec_flush_buffers(pCodecCtx); - avcodec_flush_buffers(aCodecCtx); - while( get_packet(&q_video, &packet) != 0) + avcodec_flush_buffers(vst->vCtx); + avcodec_flush_buffers(vst->aCtx); + while( get_packet(&vst->q_video, &packet) != 0) av_free_packet(&packet); - while( get_packet(&q_audio, &packet)!= 0) + while( get_packet(&vst->q_audio, &packet)!= 0) av_free_packet(&packet); flush_video(); @@ -309,7 +303,7 @@ static void flush_all() astream.count = 0; }; -void decoder() +void decoder(vst_t* vst) { int eof; AVPacket packet; @@ -326,17 +320,17 @@ void decoder() switch(decoder_state) { case PREPARE: - eof = fill_queue(); + eof = fill_queue(vst); do { - if( (q_video.size < 4*1024*1024) && + if( (vst->q_video.size < 4*1024*1024) && (eof == 0) ) { - eof = load_frame(); + eof = load_frame(vst); } - decode_video(pCodecCtx, &q_video); - ret = decode_audio(aCodecCtx, &q_audio); + decode_video(vst); + ret = decode_audio(vst->aCtx, &vst->q_audio); }while(astream.count < resampler_size*2 && ret == 1); @@ -345,13 +339,13 @@ void decoder() player_state = PLAY; case PLAY: - if( (q_video.size < 4*1024*1024) && + if( (vst->q_video.size < 4*1024*1024) && (eof == 0) ) { - eof = load_frame(); + eof = load_frame(vst); } - vret = decode_video(pCodecCtx, &q_video); - aret = decode_audio(aCodecCtx, &q_audio); + vret = decode_video(vst); + aret = decode_audio(vst->aCtx, &vst->q_audio); ret = vret | aret; if( eof && !ret) @@ -362,10 +356,10 @@ void decoder() if( (vret & aret) == -1) { - if( (q_video.size < 4*1024*1024) && + if( (vst->q_video.size < 4*1024*1024) && (eof == 0) ) { - eof = load_frame(); + eof = load_frame(vst); yield(); continue; }; @@ -385,14 +379,14 @@ void decoder() while(sound_state != STOP) delay(1); - flush_all(); + flush_all(vst); - if (pFormatCtx->start_time != AV_NOPTS_VALUE) - rewind_pos = pFormatCtx->start_time; + if (vst->fCtx->start_time != AV_NOPTS_VALUE) + rewind_pos = vst->fCtx->start_time; else rewind_pos = 0; - ret = avformat_seek_file(pFormatCtx, -1, INT64_MIN, + ret = avformat_seek_file(vst->fCtx, -1, INT64_MIN, rewind_pos, INT64_MAX, 0); decoder_state = STOP; @@ -402,7 +396,7 @@ void decoder() while(sound_state != STOP) yield(); - flush_all(); + flush_all(vst); int opts = 0; if(rewind_pos < 0) { @@ -410,27 +404,23 @@ void decoder() opts = AVSEEK_FLAG_BACKWARD; }; - if (pFormatCtx->start_time != AV_NOPTS_VALUE) - rewind_pos += pFormatCtx->start_time; + if (vst->fCtx->start_time != AV_NOPTS_VALUE) + rewind_pos += vst->fCtx->start_time; // printf("rewind %8"PRId64"\n", rewind_pos); min_pos = rewind_pos - 1000000; max_pos = rewind_pos + 1000000; - ret = avformat_seek_file(pFormatCtx, -1, INT64_MIN, + ret = avformat_seek_file(vst->fCtx, -1, INT64_MIN, rewind_pos, INT64_MAX, 0); - if (ret < 0) { printf("could not seek to position %f\n", (double)rewind_pos / AV_TIME_BASE); } - -// printf("restart\n"); decoder_state = PREPARE; break; } }; - }; diff --git a/contrib/media/fplay/fplay.h b/contrib/media/fplay/fplay.h index b81bdf2825..3fd778d38c 100644 --- a/contrib/media/fplay/fplay.h +++ b/contrib/media/fplay/fplay.h @@ -1,6 +1,6 @@ -#include "pixlib3.h" #include +#include "pixlib3.h" #define BLACK_MAGIC_SOUND #define BLACK_MAGIC_VIDEO @@ -9,6 +9,7 @@ typedef unsigned int color_t; typedef unsigned int count_t; typedef struct render render_t; +typedef struct vstate vst_t; #define HAS_LEFT (1<<0) #define HAS_TOP (1<<1) @@ -17,6 +18,7 @@ typedef struct render render_t; struct render { + vst_t *vst; uint32_t caps; uint32_t ctx_width; uint32_t ctx_height; @@ -65,7 +67,6 @@ enum player_state #define ID_VOL_LEVEL 103 #define ID_VOL_CTRL 104 - typedef struct { mutex_t lock; @@ -89,12 +90,30 @@ typedef struct { AVPacketList *last_pkt; int size; int count; - mutex_t lock; + mutex_t lock; } queue_t; int put_packet(queue_t *q, AVPacket *pkt); int get_packet(queue_t *q, AVPacket *pkt); +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 */ + + 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 :( */ + +}; + + #define DECODER_THREAD 1 #define AUDIO_THREAD 2 @@ -104,7 +123,7 @@ extern int threads_running; extern astream_t astream; extern AVRational video_time_base; -render_t *create_render(window_t *win, AVCodecContext *ctx, uint32_t flags); +render_t *create_render(vst_t *vst, window_t *win, uint32_t flags); void destroy_render(render_t *render); int init_render(render_t *render, int width, int height); void render_adjust_size(render_t *render, window_t *win); @@ -116,10 +135,11 @@ int init_audio(int format); int audio_thread(void *param); void set_audio_volume(int left, int right); -int init_video(AVCodecContext *ctx); +int init_video(vst_t* vst); int video_thread(void *param); -int decode_video(AVCodecContext *ctx, queue_t *qv); +void decoder(vst_t *vst); +int decode_video(vst_t* vst); int decode_audio(AVCodecContext *ctx, queue_t *qa); double get_master_clock(void); diff --git a/contrib/media/fplay/vaapi.c b/contrib/media/fplay/vaapi.c new file mode 100644 index 0000000000..0a9fd1f64f --- /dev/null +++ b/contrib/media/fplay/vaapi.c @@ -0,0 +1,612 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "winlib/winlib.h" +#include "fplay.h" + +extern int dfx; + +struct hw_profile +{ + enum AVCodecID av_codec; + int ff_profile; + uint64_t va_profile; +}; + + +#define ENTER() printf("enter %s\n",__FUNCTION__) +#define LEAVE() printf("leave %s\n",__FUNCTION__) +#define FAIL() printf("fail %s\n",__FUNCTION__) + + +#if DEBUG +# define D(x) x +# define bug printf +#else +# define D(x) +#endif + +#undef ARRAY_ELEMS +#define ARRAY_ELEMS(a) (sizeof(a) / sizeof((a)[0])) + +static int drm_fd = 0; +static struct vaapi_context *v_context; + +static VASurfaceID v_surface_id[4]; + +#define HAS_HEVC VA_CHECK_VERSION(0, 38, 0) +#define HAS_VP9 (VA_CHECK_VERSION(0, 38, 1) && defined(FF_PROFILE_VP9_0)) + +#define PE(av_codec_id, ff_profile, vdp_profile) \ + {AV_CODEC_ID_ ## av_codec_id, FF_PROFILE_ ## ff_profile, \ + VAProfile ## vdp_profile} + +static const struct hw_profile profiles[] = { + PE(MPEG2VIDEO, MPEG2_MAIN, MPEG2Main), + PE(MPEG2VIDEO, MPEG2_SIMPLE, MPEG2Simple), + PE(MPEG4, MPEG4_ADVANCED_SIMPLE, MPEG4AdvancedSimple), + PE(MPEG4, MPEG4_MAIN, MPEG4Main), + PE(MPEG4, MPEG4_SIMPLE, MPEG4Simple), + PE(H264, H264_HIGH, H264High), + PE(H264, H264_MAIN, H264Main), + PE(H264, H264_BASELINE, H264Baseline), + PE(VC1, VC1_ADVANCED, VC1Advanced), + PE(VC1, VC1_MAIN, VC1Main), + PE(VC1, VC1_SIMPLE, VC1Simple), + PE(WMV3, VC1_ADVANCED, VC1Advanced), + PE(WMV3, VC1_MAIN, VC1Main), + PE(WMV3, VC1_SIMPLE, VC1Simple), +#if HAS_HEVC + PE(HEVC, HEVC_MAIN, HEVCMain), + PE(HEVC, HEVC_MAIN_10, HEVCMain10), +#endif +#if HAS_VP9 + PE(VP9, VP9_0, VP9Profile0), +#endif + {0} +}; + +int va_check_codec_support(enum AVCodecID id) +{ + for (int n = 0; profiles[n].av_codec; n++) { + if (profiles[n].av_codec == id) + return 1; + } + return 0; +} + +static int vaapi_check_status(VAStatus status, const char *msg) +{ + if (status != VA_STATUS_SUCCESS) { + fprintf(stderr, "[%s] %s: %s\n", PACKAGE_NAME, msg, vaErrorStr(status)); + return 0; + } + return 1; +}; + +static const char *string_of_VADisplayAttribType(VADisplayAttribType type) +{ + switch (type) { +#define TYPE(type) \ + case VADisplayAttrib##type: return "VADisplayAttrib" #type + TYPE(Brightness); + TYPE(Contrast); + TYPE(Hue); + TYPE(Saturation); + TYPE(BackgroundColor); +#if !VA_CHECK_VERSION(0,34,0) + TYPE(DirectSurface); +#endif +#if VA_CHECK_VERSION(0,32,0) + TYPE(Rotation); +#endif +#undef TYPE + default: break; + } + return ""; +} + +static const char *string_of_VAProfile(VAProfile profile) +{ + switch (profile) { +#define PROFILE(profile) \ + case VAProfile##profile: return "VAProfile" #profile + PROFILE(MPEG2Simple); + PROFILE(MPEG2Main); + PROFILE(MPEG4Simple); + PROFILE(MPEG4AdvancedSimple); + PROFILE(MPEG4Main); +#if VA_CHECK_VERSION(0,32,0) + PROFILE(JPEGBaseline); + PROFILE(H263Baseline); + PROFILE(H264ConstrainedBaseline); +#endif + PROFILE(H264Baseline); + PROFILE(H264Main); + PROFILE(H264High); + PROFILE(VC1Simple); + PROFILE(VC1Main); + PROFILE(VC1Advanced); +#undef PROFILE + default: break; + } + return ""; +} + +static const char *string_of_VAEntrypoint(VAEntrypoint entrypoint) +{ + switch (entrypoint) { +#define ENTRYPOINT(entrypoint) \ + case VAEntrypoint##entrypoint: return "VAEntrypoint" #entrypoint + ENTRYPOINT(VLD); + ENTRYPOINT(IZZ); + ENTRYPOINT(IDCT); + ENTRYPOINT(MoComp); + ENTRYPOINT(Deblocking); +#if VA_CHECK_VERSION(0,32,0) + ENTRYPOINT(EncSlice); + ENTRYPOINT(EncPicture); +#endif +#undef ENTRYPOINT + default: break; + } + return ""; +} + +VADisplay va_open_display(void) +{ + VADisplay va_dpy; + + drm_fd = get_service("DISPLAY"); + if (drm_fd == 0) + return NULL; + + va_dpy = vaGetDisplayDRM(drm_fd); + if (va_dpy) + return va_dpy; + + drm_fd = 0; + return NULL; +}; + +int vaapi_init(VADisplay display) +{ + struct vaapi_context *vaapi; + int major_version, minor_version; + int i, num_display_attrs, max_display_attrs; + VADisplayAttribute *display_attrs = NULL; + VAStatus status; + + if (v_context) + return 0; + + if (!display) + goto error; + D(bug("VA display %p\n", display)); + + status = vaInitialize(display, &major_version, &minor_version); + if (!vaapi_check_status(status, "vaInitialize()")) + goto error; + D(bug("VA API version %d.%d\n", major_version, minor_version)); + + max_display_attrs = vaMaxNumDisplayAttributes(display); + display_attrs = malloc(max_display_attrs * sizeof(display_attrs[0])); + if (!display_attrs) + goto error; + + num_display_attrs = 0; /* XXX: workaround old GMA500 bug */ + status = vaQueryDisplayAttributes(display, display_attrs, &num_display_attrs); + if (!vaapi_check_status(status, "vaQueryDisplayAttributes()")) + goto error; + D(bug("%d display attributes available\n", num_display_attrs)); + for (i = 0; i < num_display_attrs; i++) { + VADisplayAttribute * const display_attr = &display_attrs[i]; + D(bug(" %-32s (%s/%s) min %d max %d value 0x%x\n", + string_of_VADisplayAttribType(display_attr->type), + (display_attr->flags & VA_DISPLAY_ATTRIB_GETTABLE) ? "get" : "---", + (display_attr->flags & VA_DISPLAY_ATTRIB_SETTABLE) ? "set" : "---", + display_attr->min_value, + display_attr->max_value, + display_attr->value)); + } + + if ((vaapi = calloc(1, sizeof(*vaapi))) == NULL) + goto error; + vaapi->display = display; + vaapi->config_id = VA_INVALID_ID; + vaapi->context_id = VA_INVALID_ID; +// vaapi->pic_param_buf_id = VA_INVALID_ID; +// vaapi->iq_matrix_buf_id = VA_INVALID_ID; +// vaapi->bitplane_buf_id = VA_INVALID_ID; + + v_context = vaapi; + + return 0; + +error: + free(display_attrs); + return -1; +} + + +static int has_profile(struct vaapi_context *vaapi, VAProfile profile) +{ + VAProfile *profiles; + int n_profiles; + VAStatus status; + int i; + + profiles = calloc(vaMaxNumProfiles(vaapi->display), sizeof(profiles[0])); + + status = vaQueryConfigProfiles(vaapi->display,profiles,&n_profiles); + + if (!vaapi_check_status(status, "vaQueryConfigProfiles()")) + return 0; + + D(bug("%d profiles available\n", n_profiles)); + + for (i = 0; i < n_profiles; i++) + { + if (profiles[i] == profile) + return 1; + } + return 0; +} + +static int has_entrypoint(struct vaapi_context *vaapi, VAProfile profile, VAEntrypoint entrypoint) +{ + VAEntrypoint *entrypoints; + int n_entrypoints; + VAStatus status; + int i; + + entrypoints = calloc(vaMaxNumEntrypoints(vaapi->display), sizeof(entrypoints[0])); + + status = vaQueryConfigEntrypoints(vaapi->display, profile, + entrypoints, &n_entrypoints); + if (!vaapi_check_status(status, "vaQueryConfigEntrypoints()")) + return 0; + + D(bug("%d entrypoints available for %s\n", n_entrypoints, + string_of_VAProfile(profile))); + + for (i = 0; i < n_entrypoints; i++) + { + if (entrypoints[i] == entrypoint) + return 1; + } + return 0; +} + +static int vaapi_init_decoder(VAProfile profile, + VAEntrypoint entrypoint, + unsigned int picture_width, + unsigned int picture_height) +{ + struct vaapi_context* const vaapi = v_context; + VAConfigAttrib attrib; + VAConfigID config_id = VA_INVALID_ID; + VAContextID context_id = VA_INVALID_ID; + VAStatus status; + +ENTER(); + if (!vaapi) + { + FAIL(); + return -1; + }; + + if (!has_profile(vaapi, profile)) + { + FAIL(); + return -1; + }; + + if (!has_entrypoint(vaapi, profile, entrypoint)) + { + FAIL(); + return -1; + }; + + if (vaapi->config_id != VA_INVALID_ID) + vaDestroyConfig(vaapi->display, vaapi->config_id); + + attrib.type = VAConfigAttribRTFormat; + + printf("vaGetConfigAttributes\n"); + status = vaGetConfigAttributes(vaapi->display, profile, entrypoint, + &attrib, 1); + if (!vaapi_check_status(status, "vaGetConfigAttributes()")) + { + FAIL(); + return -1; + } + + if ((attrib.value & VA_RT_FORMAT_YUV420) == 0) + { + printf("Chroma format not supported.\n"); + FAIL(); + return -1; + }; + + printf("vaCreateConfig\n"); + status = vaCreateConfig(vaapi->display, profile, entrypoint, + &attrib, 1, &config_id); + if (!vaapi_check_status(status, "vaCreateConfig()")) + { + FAIL(); + return -1; + } + + printf("vaCreateSurfaces %dx%d\n",picture_width,picture_height); + status = vaCreateSurfaces(vaapi->display, VA_RT_FORMAT_YUV420, picture_width, picture_height, + v_surface_id,4,NULL,0); + printf("v_surface_id_3 %x\n", v_surface_id[3]); + if (!vaapi_check_status(status, "vaCreateSurfaces()")) + { + FAIL(); + return -1; + }; + { + VAImage vaimage; + VABufferInfo info = {0}; + + vaDeriveImage(vaapi->display,v_surface_id[0],&vaimage); + printf("vaDeriveImage: %x fourcc: %x\n" + "offset0: %d pitch0: %d\n" + "offset1: %d pitch1: %d\n" + "offset2: %d pitch2: %d\n", + vaimage.buf, vaimage.format.fourcc, + vaimage.offsets[0],vaimage.pitches[0], + vaimage.offsets[1],vaimage.pitches[1], + vaimage.offsets[2],vaimage.pitches[2]); + + info.mem_type = VA_SURFACE_ATTRIB_MEM_TYPE_KERNEL_DRM; + vaAcquireBufferHandle(vaapi->display, vaimage.buf, &info); + printf("vaAcquireBufferHandle: %x type: %x\n" + "mem type: %x mem size: %x\n", + info.handle, info.type, info.mem_type, info.mem_size); + + vaReleaseBufferHandle(vaapi->display, vaimage.buf); + + vaDestroyImage(vaapi->display,vaimage.image_id); + }; + + printf("vaCreateContext %dx%d\n",picture_width,picture_height); + status = vaCreateContext(vaapi->display, config_id, + picture_width, picture_height, + VA_PROGRESSIVE, + v_surface_id, 4, + &context_id); + if (!vaapi_check_status(status, "vaCreateContext()")) + { + FAIL(); + return -1; + }; + + vaapi->config_id = config_id; + vaapi->context_id = context_id; + LEAVE(); + return 0; +} + + +static enum PixelFormat get_format(struct AVCodecContext *avctx, + const enum AVPixelFormat *fmt) +{ + int i, profile; + + ENTER(); + +// for (int i = 0; fmt[i] != AV_PIX_FMT_NONE; i++) +// printf(" %s", av_get_pix_fmt_name(fmt[i])); + + for (i = 0; fmt[i] != PIX_FMT_NONE; i++) { + printf("pixformat %x\n", fmt[i]); + if (fmt[i] != AV_PIX_FMT_VAAPI_VLD) + continue; + + switch (avctx->codec_id) + { + case CODEC_ID_MPEG2VIDEO: + profile = VAProfileMPEG2Main; + break; + case CODEC_ID_MPEG4: + case CODEC_ID_H263: + profile = VAProfileMPEG4AdvancedSimple; + break; + case CODEC_ID_H264: + profile = VAProfileH264High; + break; + case CODEC_ID_WMV3: + profile = VAProfileVC1Main; + break; + case CODEC_ID_VC1: + profile = VAProfileVC1Advanced; + break; + default: + profile = -1; + break; + } + if (profile >= 0) { + if (vaapi_init_decoder(profile, VAEntrypointVLD, avctx->width, avctx->height) == 0) + { + avctx->hwaccel_context = v_context; + LEAVE(); + return fmt[i]; ; + } + } + } + FAIL(); + return PIX_FMT_NONE; +} + +struct av_surface +{ + int w; + int h; + VASurfaceID id; +}; + +static void av_release_buffer(void *opaque, uint8_t *data) +{ + struct av_surface surface = *(struct av_surface*)data; +// VDPAUContext *ctx = opaque; + +// ctx->video_surface_destroy(surface); + av_freep(&data); +} + + +static int get_buffer2(AVCodecContext *avctx, AVFrame *pic, int flags) +{ + void *surface = (void *)(uintptr_t)v_surface_id[dfx]; + +// printf("%s surface %x\n", __FUNCTION__, surface); + +// pic->type= FF_BUFFER_TYPE_USER; + pic->data[3] = surface; + + struct av_surface *avsurface; + surface = av_malloc(sizeof(*avsurface)); + if (!surface) + return AVERROR(ENOMEM); + + pic->buf[0] = av_buffer_create((uint8_t*)avsurface, sizeof(*avsurface), + av_release_buffer, avctx, + AV_BUFFER_FLAG_READONLY); + return 0; +} + +struct vaapi_context va_context_storage; + +int fplay_init_context(AVCodecContext *avctx) +{ + ENTER(); + + avctx->thread_count = 1; + avctx->get_format = get_format; + avctx->get_buffer2 = get_buffer2; + + LEAVE(); + return 0; +} + +int fplay_vaapi_init(void) +{ + VADisplay dpy; + + dpy = va_open_display(); + + if (vaapi_init(dpy) < 0) + return -1; + + return 0; +} + +struct SwsContext *vacvt_ctx; + + +void va_sync() +{ + struct vaapi_context* const vaapi = v_context; + + vaSyncSurface(vaapi->display,v_surface_id[dfx]); +}; + + +void va_convert_picture(int width, int height, AVPicture *pic) +{ + uint8_t *src_data[4]; + int src_linesize[4]; + VAImage vaimage; + VAStatus status; + uint8_t *vdata; + struct vaapi_context* const vaapi = v_context; + + + va_sync(); + + status = vaDeriveImage(vaapi->display,v_surface_id[dfx],&vaimage); + if (!vaapi_check_status(status, "vaDeriveImage()")) + { + FAIL(); + return; + }; + + static int once = 2; + + if(once && dfx == 0) + { + VABufferInfo info = {0}; + + printf("vaDeriveImage: %x fourcc: %x\n" + "offset0: %d pitch0: %d\n" + "offset1: %d pitch1: %d\n" + "offset2: %d pitch2: %d\n", + vaimage.buf, vaimage.format.fourcc, + vaimage.offsets[0],vaimage.pitches[0], + vaimage.offsets[1],vaimage.pitches[1], + vaimage.offsets[2],vaimage.pitches[2]); + + info.mem_type = VA_SURFACE_ATTRIB_MEM_TYPE_KERNEL_DRM; + status = vaAcquireBufferHandle(vaapi->display, vaimage.buf, &info); + if (vaapi_check_status(status, "vaAcquireBufferHandle()")) + { + printf("vaAcquireBufferHandle: %x type: %x\n" + "mem type: %x mem size: %d\n", + info.handle, info.type, info.mem_type, info.mem_size); + + vaReleaseBufferHandle(vaapi->display, vaimage.buf); + } + once--; + }; + + src_linesize[0] = vaimage.pitches[0]; + src_linesize[1] = vaimage.pitches[1]; + src_linesize[2] = vaimage.pitches[2]; + src_linesize[3] = 0; + + status = vaMapBuffer(vaapi->display,vaimage.buf,(void **)&vdata); + if (!vaapi_check_status(status, "vaMapBuffer()")) + { + FAIL(); + return; + }; + +// printf("vdata: %x offset0: %d offset1: %d offset2: %d\n", vdata, +// vaimage.offsets[0], +// vaimage.offsets[1], +// vaimage.offsets[2]); + + src_data[0] = vdata + vaimage.offsets[0]; + src_data[1] = vdata + vaimage.offsets[1]; + src_data[2] = vdata + vaimage.offsets[2]; + src_data[3] = 0; + + vacvt_ctx = sws_getCachedContext(vacvt_ctx, width, height, AV_PIX_FMT_NV12, + width, height, AV_PIX_FMT_BGRA, + SWS_FAST_BILINEAR, NULL, NULL, NULL); + if(vacvt_ctx == NULL) + { + printf("Cannot initialize the conversion context!\n"); + return ; + }; + + +// __asm__ volatile ("int3"); + + sws_scale(vacvt_ctx, (const uint8_t* const *)src_data, src_linesize, 0, height, pic->data, pic->linesize); + + vaUnmapBuffer (vaapi->display, vaimage.buf); + vaDestroyImage(vaapi->display, vaimage.image_id); +} diff --git a/contrib/media/fplay/video.c b/contrib/media/fplay/video.c index b9c713df7f..fea9c67aa4 100644 --- a/contrib/media/fplay/video.c +++ b/contrib/media/fplay/video.c @@ -47,8 +47,6 @@ int height; AVRational video_time_base; AVFrame *Frame; -extern mutex_t driver_lock; - void get_client_rect(rect_t *rc); void flush_video() @@ -65,14 +63,14 @@ void flush_video() dfx = 0; }; -int init_video(AVCodecContext *ctx) +int init_video(vst_t *vst) { int i; - width = ctx->width; - height = ctx->height; + width = vst->vCtx->width; + height = vst->vCtx->height; - Frame = avcodec_alloc_frame(); + Frame = av_frame_alloc(); if ( Frame == NULL ) { printf("Cannot alloc video frame\n\r"); @@ -83,8 +81,8 @@ int init_video(AVCodecContext *ctx) { int ret; - ret = avpicture_alloc(&frames[i].picture, ctx->pix_fmt, - ctx->width, ctx->height); + ret = avpicture_alloc(&frames[i].picture, vst->vCtx->pix_fmt, + vst->vCtx->width, vst->vCtx->height); if ( ret != 0 ) { printf("Cannot alloc video buffer\n\r"); @@ -95,13 +93,13 @@ int init_video(AVCodecContext *ctx) frames[i].ready = 0; }; - create_thread(video_thread, ctx, 1024*1024); + create_thread(video_thread, vst, 1024*1024); delay(50); return 1; }; -int decode_video(AVCodecContext *ctx, queue_t *qv) +int decode_video(vst_t* vst) { AVPacket pkt; double pts; @@ -111,7 +109,7 @@ int decode_video(AVCodecContext *ctx, queue_t *qv) if(frames[dfx].ready != 0 ) return -1; - if( get_packet(qv, &pkt) == 0 ) + if( get_packet(&vst->q_video, &pkt) == 0 ) return 0; /* @@ -132,9 +130,11 @@ int decode_video(AVCodecContext *ctx, queue_t *qv) { frameFinished = 0; - ctx->reordered_opaque = pkt.pts; + vst->vCtx->reordered_opaque = pkt.pts; - if(avcodec_decode_video2(ctx, Frame, &frameFinished, &pkt) <= 0) + mutex_lock(&vst->gpu_lock); + + if(avcodec_decode_video2(vst->vCtx, Frame, &frameFinished, &pkt) <= 0) printf("video decoder error\n"); if(frameFinished) @@ -155,7 +155,7 @@ int decode_video(AVCodecContext *ctx, queue_t *qv) av_image_copy(dst_pic->data, dst_pic->linesize, (const uint8_t**)Frame->data, - Frame->linesize, ctx->pix_fmt, ctx->width, ctx->height); + Frame->linesize, vst->vCtx->pix_fmt, vst->vCtx->width, vst->vCtx->height); frames[dfx].pts = pts*1000.0; @@ -165,6 +165,8 @@ int decode_video(AVCodecContext *ctx, queue_t *qv) dfx&= 3; frames_count++; }; + mutex_unlock(&vst->gpu_lock); + }; av_free_packet(&pkt); @@ -386,9 +388,6 @@ int MainWindowProc(ctrl_t *ctrl, uint32_t msg, uint32_t arg1, uint32_t arg2) #define VERSION_A 1 -extern queue_t q_video; -extern queue_t q_audio; - void render_time(render_t *render) { progress_t *prg = main_render->win->panel.prg; @@ -547,7 +546,7 @@ extern char *movie_file; int video_thread(void *param) { - AVCodecContext *ctx = param; + vst_t *vst = param; window_t *MainWindow; init_winlib(); @@ -559,9 +558,7 @@ int video_thread(void *param) show_window(MainWindow, NORMAL); -// __asm__ __volatile__("int3"); - - main_render = create_render(MainWindow, ctx, HW_TEX_BLIT|HW_BIT_BLIT); + main_render = create_render(vst, MainWindow, HW_TEX_BLIT|HW_BIT_BLIT); if( main_render == NULL) { printf("Cannot create render\n\r"); @@ -587,7 +584,7 @@ int video_thread(void *param) void draw_hw_picture(render_t *render, AVPicture *picture); void draw_sw_picture(render_t *render, AVPicture *picture); -render_t *create_render(window_t *win, AVCodecContext *ctx, uint32_t flags) +render_t *create_render(vst_t *vst, window_t *win, uint32_t flags) { render_t *render; @@ -600,11 +597,12 @@ render_t *create_render(window_t *win, AVCodecContext *ctx, uint32_t flags) render = (render_t*)malloc(sizeof(render_t)); memset(render, 0, sizeof(render_t)); + render->vst = vst; render->win = win; - render->ctx_width = ctx->width; - render->ctx_height = ctx->height; - render->ctx_format = ctx->pix_fmt; + render->ctx_width = vst->vCtx->width; + render->ctx_height = vst->vCtx->height; + render->ctx_format = vst->vCtx->pix_fmt; render->caps = pxInit(1); @@ -845,7 +843,7 @@ void draw_hw_picture(render_t *render, AVPicture *picture) cvt_ctx = sws_getCachedContext(cvt_ctx, render->ctx_width, render->ctx_height, render->ctx_format, - dst_width, dst_height, PIX_FMT_BGRA, + dst_width, dst_height, AV_PIX_FMT_BGRA, SWS_FAST_BILINEAR, NULL, NULL, NULL); if(cvt_ctx == NULL) { @@ -877,6 +875,7 @@ void draw_hw_picture(render_t *render, AVPicture *picture) picture->linesize, 0, render->ctx_height, data, linesize); // printf("sws_scale\n"); + mutex_lock(&render->vst->gpu_lock); if(render->caps & HW_TEX_BLIT) { @@ -899,6 +898,7 @@ void draw_hw_picture(render_t *render, AVPicture *picture) CAPTION_HEIGHT+render->rcvideo.t, render->rcvideo.r, render->rcvideo.b, 0, 0); }; + mutex_unlock(&render->vst->gpu_lock); render->last_bitmap = bitmap; render->target++; @@ -920,7 +920,7 @@ void draw_sw_picture(render_t *render, AVPicture *picture) render->ctx_width, render->ctx_height, render->ctx_format, render->rcvideo.r, render->rcvideo.b, - PIX_FMT_BGRA, SWS_FAST_BILINEAR, NULL, NULL, NULL); + AV_PIX_FMT_BGRA, SWS_FAST_BILINEAR, NULL, NULL, NULL); if(cvt_ctx == NULL) { printf("Cannot initialize the conversion context!\n");