Fplay: ffmpeg-2.5 compatible edition

git-svn-id: svn://kolibrios.org@6117 a494cfbc-eb01-0410-851d-a64ba20cac60
This commit is contained in:
Sergey Semyonov (Serge) 2016-02-01 15:10:02 +00:00
parent eaf749c10f
commit 7218b51863
6 changed files with 759 additions and 139 deletions

View File

@ -19,7 +19,7 @@ INCLUDES+=-I$(SDK_DIR)/sources/freetype/include
#-I$(SDK_DIR)/sources/vaapi/libva-1.4.1 #-I$(SDK_DIR)/sources/vaapi/libva-1.4.1
#DEFINES= -DDEBUG=1 -DPACKAGE_NAME=\"Fplay-vaapi\" #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 LIBS+= -lswresample.dll -lsound -lpixlib3 -lfreetype.dll -lva.dll -lgcc -lc.dll -lapp
LIBPATH:= -L$(LIB_DIR) -L/home/autobuild/tools/win32/mingw32/lib LIBPATH:= -L$(LIB_DIR) -L/home/autobuild/tools/win32/mingw32/lib

View File

@ -23,8 +23,6 @@ volatile enum player_state player_state;
volatile enum player_state decoder_state; volatile enum player_state decoder_state;
volatile enum player_state sound_state; volatile enum player_state sound_state;
extern mutex_t driver_lock;
static SNDBUF hBuff; static SNDBUF hBuff;
static int snd_format; static int snd_format;
@ -108,7 +106,7 @@ int decode_audio(AVCodecContext *ctx, queue_t *qa)
if (!aFrame) if (!aFrame)
{ {
if (!(aFrame = avcodec_alloc_frame())) if (!(aFrame = av_frame_alloc()))
return -1; return -1;
} else } else
avcodec_get_frame_defaults(aFrame); avcodec_get_frame_defaults(aFrame);

View File

@ -25,14 +25,7 @@ uint32_t win_width, win_height;
void decoder(); void decoder();
int fplay_init_context(AVCodecContext *avctx); int fplay_init_context(AVCodecContext *avctx);
AVFormatContext *pFormatCtx;
AVCodecContext *pCodecCtx;
AVCodecContext *aCodecCtx;
AVCodec *pCodec;
AVCodec *aCodec;
AVFrame *pFrame; AVFrame *pFrame;
int videoStream;
int audioStream;
int have_sound = 0; int have_sound = 0;
@ -44,8 +37,7 @@ char *movie_file;
void flush_video(); void flush_video();
queue_t q_video;
queue_t q_audio;
int64_t rewind_pos; int64_t rewind_pos;
int64_t stream_duration; int64_t stream_duration;
@ -54,15 +46,17 @@ int threads_running = DECODER_THREAD;
extern double audio_base; 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 main( int argc, char *argv[])
{ {
int i; static vst_t vst;
int i, ret;
char *file_name, *dot; char *file_name, *dot;
if(argc < 2) if(argc < 2)
@ -84,16 +78,16 @@ int main( int argc, char *argv[])
avdevice_register_all(); avdevice_register_all();
av_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); printf("Cannot open file %s\n\r", movie_file);
return -1; // Couldn't open file return -1; // Couldn't open file
}; };
pFormatCtx->flags |= AVFMT_FLAG_GENPTS; vst.fCtx->flags |= AVFMT_FLAG_GENPTS;
// Retrieve stream information // 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"); printf("Cannot find streams\n\r");
return -1; return -1;
@ -109,32 +103,33 @@ int main( int argc, char *argv[])
} }
else movie_file = file_name; else movie_file = file_name;
stream_duration = pFormatCtx->duration; stream_duration = vst.fCtx->duration;
// Find the first video stream // Find the first video stream
videoStream=-1; vst.vStream = -1;
audioStream=-1; vst.aStream = -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;
} for(i=0; i < vst.fCtx->nb_streams; i++)
if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_AUDIO && {
audioStream < 0) 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) 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"); printf("Video stream not detected\n\r");
return -1; // Didn't find a video stream return -1; // Didn't find a video stream
@ -143,59 +138,60 @@ int main( int argc, char *argv[])
// __asm__ __volatile__("int3"); // __asm__ __volatile__("int3");
// Get a pointer to the codec context for the video stream // Get a pointer to the codec context for the video stream
pCodecCtx = pFormatCtx->streams[videoStream]->codec; vst.vCtx = vst.fCtx->streams[vst.vStream]->codec;
aCodecCtx = pFormatCtx->streams[audioStream]->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);
if(vst.vCodec == NULL)
pCodec=avcodec_find_decoder(pCodecCtx->codec_id); {
// printf("ctx->pix_fmt %d\n", pCodecCtx->pix_fmt);
if(pCodec==NULL) {
printf("Unsupported codec with id %d for input stream %d\n", 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 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", printf("Error while opening codec for input stream %d\n",
videoStream); vst.vStream);
return -1; // Could not open codec return -1; // Could not open codec
}; };
// printf("ctx->pix_fmt %d\n", pCodecCtx->pix_fmt);
mutex_init(&q_video.lock); mutex_init(&vst.q_video.lock);
mutex_init(&q_audio.lock); mutex_init(&vst.q_audio.lock);
mutex_init(&vst.gpu_lock);
if (aCodecCtx->channels > 0) if (vst.aCtx->channels > 0)
aCodecCtx->request_channels = FFMIN(2, aCodecCtx->channels); vst.aCtx->request_channels = FFMIN(2, vst.aCtx->channels);
else 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; WAVEHEADER whdr;
int fmt; int fmt;
int channels; int channels;
printf("audio stream rate %d channels %d format %d\n", 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_id = 0x46464952;
whdr.riff_format = 0x45564157; whdr.riff_format = 0x45564157;
whdr.wFormatTag = 0x01; whdr.wFormatTag = 0x01;
whdr.nSamplesPerSec = aCodecCtx->sample_rate; whdr.nSamplesPerSec = vst.aCtx->sample_rate;
whdr.nChannels = 2; whdr.nChannels = 2;
whdr.wBitsPerSample = 16; whdr.wBitsPerSample = 16;
sample_rate = aCodecCtx->sample_rate; sample_rate = vst.aCtx->sample_rate;
fmt = test_wav(&whdr); fmt = test_wav(&whdr);
@ -222,10 +218,10 @@ int main( int argc, char *argv[])
} }
else printf("Unsupported audio codec!\n"); else printf("Unsupported audio codec!\n");
if( !init_video(pCodecCtx)) if(!init_video(&vst))
return 0; return 0;
decoder(); decoder(&vst);
// Free the YUV frame // Free the YUV frame
av_free(pFrame); av_free(pFrame);
@ -240,31 +236,31 @@ int main( int argc, char *argv[])
if(astream.lock.handle) if(astream.lock.handle)
mutex_destroy(&astream.lock); mutex_destroy(&astream.lock);
mutex_destroy(&q_video.lock); mutex_destroy(&vst.q_video.lock);
mutex_destroy(&q_audio.lock); mutex_destroy(&vst.q_audio.lock);
return 0; return 0;
} }
static int load_frame() static int load_frame(vst_t *vst)
{ {
AVPacket packet; AVPacket packet;
int err; int err;
err = av_read_frame(pFormatCtx, &packet); err = av_read_frame(vst->fCtx, &packet);
if( err == 0) if( err == 0)
{ {
if(packet.stream_index==videoStream) if(packet.stream_index == vst->vStream)
put_packet(&q_video, &packet); put_packet(&vst->q_video, &packet);
else if( (packet.stream_index == audioStream) && else if( (packet.stream_index == vst->aStream) &&
(have_sound != 0) ) (have_sound != 0) )
{ {
put_packet(&q_audio, &packet); put_packet(&vst->q_audio, &packet);
if(audio_base == -1.0) if(audio_base == -1.0)
{ {
if (packet.pts != AV_NOPTS_VALUE) 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); // 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; int err = 0;
AVPacket packet; AVPacket packet;
while( (q_video.size < 4*1024*1024) && while( (vst->q_video.size < 4*1024*1024) && !err )
!err ) err = load_frame(vst);
err = load_frame();
return err; return err;
}; };
static void flush_all() static void flush_all(vst_t* vst)
{ {
AVPacket packet; AVPacket packet;
avcodec_flush_buffers(pCodecCtx); avcodec_flush_buffers(vst->vCtx);
avcodec_flush_buffers(aCodecCtx); avcodec_flush_buffers(vst->aCtx);
while( get_packet(&q_video, &packet) != 0) while( get_packet(&vst->q_video, &packet) != 0)
av_free_packet(&packet); av_free_packet(&packet);
while( get_packet(&q_audio, &packet)!= 0) while( get_packet(&vst->q_audio, &packet)!= 0)
av_free_packet(&packet); av_free_packet(&packet);
flush_video(); flush_video();
@ -309,7 +303,7 @@ static void flush_all()
astream.count = 0; astream.count = 0;
}; };
void decoder() void decoder(vst_t* vst)
{ {
int eof; int eof;
AVPacket packet; AVPacket packet;
@ -326,17 +320,17 @@ void decoder()
switch(decoder_state) switch(decoder_state)
{ {
case PREPARE: case PREPARE:
eof = fill_queue(); eof = fill_queue(vst);
do do
{ {
if( (q_video.size < 4*1024*1024) && if( (vst->q_video.size < 4*1024*1024) &&
(eof == 0) ) (eof == 0) )
{ {
eof = load_frame(); eof = load_frame(vst);
} }
decode_video(pCodecCtx, &q_video); decode_video(vst);
ret = decode_audio(aCodecCtx, &q_audio); ret = decode_audio(vst->aCtx, &vst->q_audio);
}while(astream.count < resampler_size*2 && }while(astream.count < resampler_size*2 &&
ret == 1); ret == 1);
@ -345,13 +339,13 @@ void decoder()
player_state = PLAY; player_state = PLAY;
case PLAY: case PLAY:
if( (q_video.size < 4*1024*1024) && if( (vst->q_video.size < 4*1024*1024) &&
(eof == 0) ) (eof == 0) )
{ {
eof = load_frame(); eof = load_frame(vst);
} }
vret = decode_video(pCodecCtx, &q_video); vret = decode_video(vst);
aret = decode_audio(aCodecCtx, &q_audio); aret = decode_audio(vst->aCtx, &vst->q_audio);
ret = vret | aret; ret = vret | aret;
if( eof && !ret) if( eof && !ret)
@ -362,10 +356,10 @@ void decoder()
if( (vret & aret) == -1) if( (vret & aret) == -1)
{ {
if( (q_video.size < 4*1024*1024) && if( (vst->q_video.size < 4*1024*1024) &&
(eof == 0) ) (eof == 0) )
{ {
eof = load_frame(); eof = load_frame(vst);
yield(); yield();
continue; continue;
}; };
@ -385,14 +379,14 @@ void decoder()
while(sound_state != STOP) while(sound_state != STOP)
delay(1); delay(1);
flush_all(); flush_all(vst);
if (pFormatCtx->start_time != AV_NOPTS_VALUE) if (vst->fCtx->start_time != AV_NOPTS_VALUE)
rewind_pos = pFormatCtx->start_time; rewind_pos = vst->fCtx->start_time;
else else
rewind_pos = 0; 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); rewind_pos, INT64_MAX, 0);
decoder_state = STOP; decoder_state = STOP;
@ -402,7 +396,7 @@ void decoder()
while(sound_state != STOP) while(sound_state != STOP)
yield(); yield();
flush_all(); flush_all(vst);
int opts = 0; int opts = 0;
if(rewind_pos < 0) if(rewind_pos < 0)
{ {
@ -410,27 +404,23 @@ void decoder()
opts = AVSEEK_FLAG_BACKWARD; opts = AVSEEK_FLAG_BACKWARD;
}; };
if (pFormatCtx->start_time != AV_NOPTS_VALUE) if (vst->fCtx->start_time != AV_NOPTS_VALUE)
rewind_pos += pFormatCtx->start_time; rewind_pos += vst->fCtx->start_time;
// printf("rewind %8"PRId64"\n", rewind_pos); // printf("rewind %8"PRId64"\n", rewind_pos);
min_pos = rewind_pos - 1000000; min_pos = rewind_pos - 1000000;
max_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); rewind_pos, INT64_MAX, 0);
if (ret < 0) if (ret < 0)
{ {
printf("could not seek to position %f\n", printf("could not seek to position %f\n",
(double)rewind_pos / AV_TIME_BASE); (double)rewind_pos / AV_TIME_BASE);
} }
// printf("restart\n");
decoder_state = PREPARE; decoder_state = PREPARE;
break; break;
} }
}; };
}; };

View File

@ -1,6 +1,6 @@
#include "pixlib3.h"
#include <libsync.h> #include <libsync.h>
#include "pixlib3.h"
#define BLACK_MAGIC_SOUND #define BLACK_MAGIC_SOUND
#define BLACK_MAGIC_VIDEO #define BLACK_MAGIC_VIDEO
@ -9,6 +9,7 @@ typedef unsigned int color_t;
typedef unsigned int count_t; typedef unsigned int count_t;
typedef struct render render_t; typedef struct render render_t;
typedef struct vstate vst_t;
#define HAS_LEFT (1<<0) #define HAS_LEFT (1<<0)
#define HAS_TOP (1<<1) #define HAS_TOP (1<<1)
@ -17,6 +18,7 @@ typedef struct render render_t;
struct render struct render
{ {
vst_t *vst;
uint32_t caps; uint32_t caps;
uint32_t ctx_width; uint32_t ctx_width;
uint32_t ctx_height; uint32_t ctx_height;
@ -65,7 +67,6 @@ enum player_state
#define ID_VOL_LEVEL 103 #define ID_VOL_LEVEL 103
#define ID_VOL_CTRL 104 #define ID_VOL_CTRL 104
typedef struct typedef struct
{ {
mutex_t lock; mutex_t lock;
@ -89,12 +90,30 @@ typedef struct {
AVPacketList *last_pkt; AVPacketList *last_pkt;
int size; int size;
int count; int count;
mutex_t lock; mutex_t lock;
} queue_t; } queue_t;
int put_packet(queue_t *q, AVPacket *pkt); int put_packet(queue_t *q, AVPacket *pkt);
int get_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 DECODER_THREAD 1
#define AUDIO_THREAD 2 #define AUDIO_THREAD 2
@ -104,7 +123,7 @@ extern int threads_running;
extern astream_t astream; extern astream_t astream;
extern AVRational video_time_base; 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); void destroy_render(render_t *render);
int init_render(render_t *render, int width, int height); int init_render(render_t *render, int width, int height);
void render_adjust_size(render_t *render, window_t *win); void render_adjust_size(render_t *render, window_t *win);
@ -116,10 +135,11 @@ int init_audio(int format);
int audio_thread(void *param); int audio_thread(void *param);
void set_audio_volume(int left, int right); 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 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); int decode_audio(AVCodecContext *ctx, queue_t *qa);
double get_master_clock(void); double get_master_clock(void);

612
contrib/media/fplay/vaapi.c Normal file
View File

@ -0,0 +1,612 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
#include <libavcodec/vaapi.h>
#include <va/va.h>
#include <va/va_drmcommon.h>
#include <va/drm/va_drm.h>
#include <kos32sys.h>
#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 "<unknown>";
}
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 "<unknown>";
}
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 "<unknown>";
}
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);
}

View File

@ -47,8 +47,6 @@ int height;
AVRational video_time_base; AVRational video_time_base;
AVFrame *Frame; AVFrame *Frame;
extern mutex_t driver_lock;
void get_client_rect(rect_t *rc); void get_client_rect(rect_t *rc);
void flush_video() void flush_video()
@ -65,14 +63,14 @@ void flush_video()
dfx = 0; dfx = 0;
}; };
int init_video(AVCodecContext *ctx) int init_video(vst_t *vst)
{ {
int i; int i;
width = ctx->width; width = vst->vCtx->width;
height = ctx->height; height = vst->vCtx->height;
Frame = avcodec_alloc_frame(); Frame = av_frame_alloc();
if ( Frame == NULL ) if ( Frame == NULL )
{ {
printf("Cannot alloc video frame\n\r"); printf("Cannot alloc video frame\n\r");
@ -83,8 +81,8 @@ int init_video(AVCodecContext *ctx)
{ {
int ret; int ret;
ret = avpicture_alloc(&frames[i].picture, ctx->pix_fmt, ret = avpicture_alloc(&frames[i].picture, vst->vCtx->pix_fmt,
ctx->width, ctx->height); vst->vCtx->width, vst->vCtx->height);
if ( ret != 0 ) if ( ret != 0 )
{ {
printf("Cannot alloc video buffer\n\r"); printf("Cannot alloc video buffer\n\r");
@ -95,13 +93,13 @@ int init_video(AVCodecContext *ctx)
frames[i].ready = 0; frames[i].ready = 0;
}; };
create_thread(video_thread, ctx, 1024*1024); create_thread(video_thread, vst, 1024*1024);
delay(50); delay(50);
return 1; return 1;
}; };
int decode_video(AVCodecContext *ctx, queue_t *qv) int decode_video(vst_t* vst)
{ {
AVPacket pkt; AVPacket pkt;
double pts; double pts;
@ -111,7 +109,7 @@ int decode_video(AVCodecContext *ctx, queue_t *qv)
if(frames[dfx].ready != 0 ) if(frames[dfx].ready != 0 )
return -1; return -1;
if( get_packet(qv, &pkt) == 0 ) if( get_packet(&vst->q_video, &pkt) == 0 )
return 0; return 0;
/* /*
@ -132,9 +130,11 @@ int decode_video(AVCodecContext *ctx, queue_t *qv)
{ {
frameFinished = 0; 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"); printf("video decoder error\n");
if(frameFinished) if(frameFinished)
@ -155,7 +155,7 @@ int decode_video(AVCodecContext *ctx, queue_t *qv)
av_image_copy(dst_pic->data, dst_pic->linesize, av_image_copy(dst_pic->data, dst_pic->linesize,
(const uint8_t**)Frame->data, (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; frames[dfx].pts = pts*1000.0;
@ -165,6 +165,8 @@ int decode_video(AVCodecContext *ctx, queue_t *qv)
dfx&= 3; dfx&= 3;
frames_count++; frames_count++;
}; };
mutex_unlock(&vst->gpu_lock);
}; };
av_free_packet(&pkt); 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 #define VERSION_A 1
extern queue_t q_video;
extern queue_t q_audio;
void render_time(render_t *render) void render_time(render_t *render)
{ {
progress_t *prg = main_render->win->panel.prg; progress_t *prg = main_render->win->panel.prg;
@ -547,7 +546,7 @@ extern char *movie_file;
int video_thread(void *param) int video_thread(void *param)
{ {
AVCodecContext *ctx = param; vst_t *vst = param;
window_t *MainWindow; window_t *MainWindow;
init_winlib(); init_winlib();
@ -559,9 +558,7 @@ int video_thread(void *param)
show_window(MainWindow, NORMAL); show_window(MainWindow, NORMAL);
// __asm__ __volatile__("int3"); main_render = create_render(vst, MainWindow, HW_TEX_BLIT|HW_BIT_BLIT);
main_render = create_render(MainWindow, ctx, HW_TEX_BLIT|HW_BIT_BLIT);
if( main_render == NULL) if( main_render == NULL)
{ {
printf("Cannot create render\n\r"); 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_hw_picture(render_t *render, AVPicture *picture);
void draw_sw_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; 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)); render = (render_t*)malloc(sizeof(render_t));
memset(render, 0, sizeof(render_t)); memset(render, 0, sizeof(render_t));
render->vst = vst;
render->win = win; render->win = win;
render->ctx_width = ctx->width; render->ctx_width = vst->vCtx->width;
render->ctx_height = ctx->height; render->ctx_height = vst->vCtx->height;
render->ctx_format = ctx->pix_fmt; render->ctx_format = vst->vCtx->pix_fmt;
render->caps = pxInit(1); render->caps = pxInit(1);
@ -845,7 +843,7 @@ void draw_hw_picture(render_t *render, AVPicture *picture)
cvt_ctx = sws_getCachedContext(cvt_ctx, cvt_ctx = sws_getCachedContext(cvt_ctx,
render->ctx_width, render->ctx_height, render->ctx_format, 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); SWS_FAST_BILINEAR, NULL, NULL, NULL);
if(cvt_ctx == 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); picture->linesize, 0, render->ctx_height, data, linesize);
// printf("sws_scale\n"); // printf("sws_scale\n");
mutex_lock(&render->vst->gpu_lock);
if(render->caps & HW_TEX_BLIT) if(render->caps & HW_TEX_BLIT)
{ {
@ -899,6 +898,7 @@ void draw_hw_picture(render_t *render, AVPicture *picture)
CAPTION_HEIGHT+render->rcvideo.t, CAPTION_HEIGHT+render->rcvideo.t,
render->rcvideo.r, render->rcvideo.b, 0, 0); render->rcvideo.r, render->rcvideo.b, 0, 0);
}; };
mutex_unlock(&render->vst->gpu_lock);
render->last_bitmap = bitmap; render->last_bitmap = bitmap;
render->target++; render->target++;
@ -920,7 +920,7 @@ void draw_sw_picture(render_t *render, AVPicture *picture)
render->ctx_width, render->ctx_height, render->ctx_width, render->ctx_height,
render->ctx_format, render->ctx_format,
render->rcvideo.r, render->rcvideo.b, 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) if(cvt_ctx == NULL)
{ {
printf("Cannot initialize the conversion context!\n"); printf("Cannot initialize the conversion context!\n");