@ -105,6 +105,8 @@ const int program_birth_year = 2003;
# define CURSOR_HIDE_DELAY 1000000
# define USE_ONEPASS_SUBTITLE_RENDER 1
static unsigned sws_flags = SWS_BICUBIC ;
typedef struct MyAVPacketList {
@ -152,17 +154,17 @@ typedef struct Clock {
typedef struct Frame {
AVFrame * frame ;
AVSubtitle sub ;
AVSubtitleRect * * subrects ; /* rescaled subtitle rectangles in yuva */
int serial ;
double pts ; /* presentation timestamp for the frame */
double duration ; /* estimated duration of the frame */
int64_t pos ; /* byte position of the frame in the input file */
SDL_Overlay * bmp ;
SDL_Texture * bmp ;
int allocated ;
int reallocate ;
int width ;
int height ;
int format ;
AVRational sar ;
int uploaded ;
} Frame ;
typedef struct FrameQueue {
@ -272,6 +274,8 @@ typedef struct VideoState {
FFTSample * rdft_data ;
int xpos ;
double last_vis_time ;
SDL_Texture * vis_texture ;
SDL_Texture * sub_texture ;
int subtitle_stream ;
AVStream * subtitle_st ;
@ -284,11 +288,8 @@ typedef struct VideoState {
AVStream * video_st ;
PacketQueue videoq ;
double max_frame_duration ; // maximum duration of a frame - above this, we consider the jump a timestamp discontinuity
# if !CONFIG_AVFILTER
struct SwsContext * img_convert_ctx ;
# endif
struct SwsContext * sub_convert_ctx ;
SDL_Rect last_display_rect ;
int eof ;
char * filename ;
@ -313,8 +314,6 @@ typedef struct VideoState {
static AVInputFormat * file_iformat ;
static const char * input_filename ;
static const char * window_title ;
static int fs_screen_width ;
static int fs_screen_height ;
static int default_width = 640 ;
static int default_height = 480 ;
static int screen_width = 0 ;
@ -362,7 +361,8 @@ static AVPacket flush_pkt;
# define FF_ALLOC_EVENT (SDL_USEREVENT)
# define FF_QUIT_EVENT (SDL_USEREVENT + 2)
static SDL_Surface * screen ;
static SDL_Window * window ;
static SDL_Renderer * renderer ;
# if CONFIG_AVFILTER
static int opt_add_vfilter ( void * optctx , const char * opt , const char * arg )
@ -650,12 +650,6 @@ static void decoder_destroy(Decoder *d) {
static void frame_queue_unref_item ( Frame * vp )
{
int i ;
for ( i = 0 ; i < vp - > sub . num_rects ; i + + ) {
av_freep ( & vp - > subrects [ i ] - > data [ 0 ] ) ;
av_freep ( & vp - > subrects [ i ] ) ;
}
av_freep ( & vp - > subrects ) ;
av_frame_unref ( vp - > frame ) ;
avsubtitle_free ( & vp - > sub ) ;
}
@ -798,113 +792,47 @@ static void decoder_abort(Decoder *d, FrameQueue *fq)
packet_queue_flush ( d - > queue ) ;
}
static inline void fill_rectangle ( SDL_Surface * screen ,
int x , int y , int w , int h , int color , int update )
static inline void fill_rectangle ( int x , int y , int w , int h )
{
SDL_Rect rect ;
rect . x = x ;
rect . y = y ;
rect . w = w ;
rect . h = h ;
SDL_FillRect ( screen , & rect , color ) ;
if ( update & & w > 0 & & h > 0 )
SDL_UpdateRect ( screen , x , y , w , h ) ;
}
/* draw only the border of a rectangle */
static void fill_border ( int xleft , int ytop , int width , int height , int x , int y , int w , int h , int color , int update )
{
int w1 , w2 , h1 , h2 ;
/* fill the background */
w1 = x ;
if ( w1 < 0 )
w1 = 0 ;
w2 = width - ( x + w ) ;
if ( w2 < 0 )
w2 = 0 ;
h1 = y ;
if ( h1 < 0 )
h1 = 0 ;
h2 = height - ( y + h ) ;
if ( h2 < 0 )
h2 = 0 ;
fill_rectangle ( screen ,
xleft , ytop ,
w1 , height ,
color , update ) ;
fill_rectangle ( screen ,
xleft + width - w2 , ytop ,
w2 , height ,
color , update ) ;
fill_rectangle ( screen ,
xleft + w1 , ytop ,
width - w1 - w2 , h1 ,
color , update ) ;
fill_rectangle ( screen ,
xleft + w1 , ytop + height - h2 ,
width - w1 - w2 , h2 ,
color , update ) ;
}
# define ALPHA_BLEND(a, oldp, newp, s)\
( ( ( ( oldp < < s ) * ( 255 - ( a ) ) ) + ( newp * ( a ) ) ) / ( 255 < < s ) )
# define BPP 1
static void blend_subrect ( uint8_t * * data , int * linesize , const AVSubtitleRect * rect , int imgw , int imgh )
{
int x , y , Y , U , V , A ;
uint8_t * lum , * cb , * cr ;
int dstx , dsty , dstw , dsth ;
const AVSubtitleRect * src = rect ;
dstw = av_clip ( rect - > w , 0 , imgw ) ;
dsth = av_clip ( rect - > h , 0 , imgh ) ;
dstx = av_clip ( rect - > x , 0 , imgw - dstw ) ;
dsty = av_clip ( rect - > y , 0 , imgh - dsth ) ;
lum = data [ 0 ] + dstx + dsty * linesize [ 0 ] ;
cb = data [ 1 ] + dstx / 2 + ( dsty > > 1 ) * linesize [ 1 ] ;
cr = data [ 2 ] + dstx / 2 + ( dsty > > 1 ) * linesize [ 2 ] ;
for ( y = 0 ; y < dsth ; y + + ) {
for ( x = 0 ; x < dstw ; x + + ) {
Y = src - > data [ 0 ] [ x + y * src - > linesize [ 0 ] ] ;
A = src - > data [ 3 ] [ x + y * src - > linesize [ 3 ] ] ;
lum [ 0 ] = ALPHA_BLEND ( A , lum [ 0 ] , Y , 0 ) ;
lum + + ;
}
lum + = linesize [ 0 ] - dstw ;
}
for ( y = 0 ; y < dsth / 2 ; y + + ) {
for ( x = 0 ; x < dstw / 2 ; x + + ) {
U = src - > data [ 1 ] [ x + y * src - > linesize [ 1 ] ] ;
V = src - > data [ 2 ] [ x + y * src - > linesize [ 2 ] ] ;
A = src - > data [ 3 ] [ 2 * x + 2 * y * src - > linesize [ 3 ] ]
+ src - > data [ 3 ] [ 2 * x + 1 + 2 * y * src - > linesize [ 3 ] ]
+ src - > data [ 3 ] [ 2 * x + 1 + ( 2 * y + 1 ) * src - > linesize [ 3 ] ]
+ src - > data [ 3 ] [ 2 * x + ( 2 * y + 1 ) * src - > linesize [ 3 ] ] ;
cb [ 0 ] = ALPHA_BLEND ( A > > 2 , cb [ 0 ] , U , 0 ) ;
cr [ 0 ] = ALPHA_BLEND ( A > > 2 , cr [ 0 ] , V , 0 ) ;
cb + + ;
cr + + ;
}
cb + = linesize [ 1 ] - dstw / 2 ;
cr + = linesize [ 2 ] - dstw / 2 ;
}
if ( w & & h )
SDL_RenderFillRect ( renderer , & rect ) ;
}
static void free_picture ( Frame * vp )
{
if ( vp - > bmp ) {
SDL_FreeYUVOverlay ( vp - > bmp ) ;
SDL_DestroyTexture ( vp - > bmp ) ;
vp - > bmp = NULL ;
}
}
static int realloc_texture ( SDL_Texture * * texture , Uint32 new_format , int new_width , int new_height , SDL_BlendMode blendmode , int init_texture )
{
Uint32 format ;
int access , w , h ;
if ( SDL_QueryTexture ( * texture , & format , & access , & w , & h ) < 0 | | new_width ! = w | | new_height ! = h | | new_format ! = format ) {
void * pixels ;
int pitch ;
SDL_DestroyTexture ( * texture ) ;
if ( ! ( * texture = SDL_CreateTexture ( renderer , new_format , SDL_TEXTUREACCESS_STREAMING , new_width , new_height ) ) )
return - 1 ;
if ( SDL_SetTextureBlendMode ( * texture , blendmode ) < 0 )
return - 1 ;
if ( init_texture ) {
if ( SDL_LockTexture ( * texture , NULL , & pixels , & pitch ) < 0 )
return - 1 ;
memset ( pixels , 0 , pitch * new_height ) ;
SDL_UnlockTexture ( * texture ) ;
}
}
return 0 ;
}
static void calculate_display_rect ( SDL_Rect * rect ,
int scr_xleft , int scr_ytop , int scr_width , int scr_height ,
int pic_width , int pic_height , AVRational pic_sar )
@ -936,12 +864,44 @@ static void calculate_display_rect(SDL_Rect *rect,
rect - > h = FFMAX ( height , 1 ) ;
}
static int upload_texture ( SDL_Texture * tex , AVFrame * frame , struct SwsContext * * img_convert_ctx ) {
int ret = 0 ;
switch ( frame - > format ) {
case AV_PIX_FMT_YUV420P :
ret = SDL_UpdateYUVTexture ( tex , NULL , frame - > data [ 0 ] , frame - > linesize [ 0 ] ,
frame - > data [ 1 ] , frame - > linesize [ 1 ] ,
frame - > data [ 2 ] , frame - > linesize [ 2 ] ) ;
break ;
case AV_PIX_FMT_BGRA :
ret = SDL_UpdateTexture ( tex , NULL , frame - > data [ 0 ] , frame - > linesize [ 0 ] ) ;
break ;
default :
/* 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 ,
AV_PIX_FMT_BGRA , sws_flags , NULL , NULL , NULL ) ;
if ( * img_convert_ctx ! = NULL ) {
uint8_t * pixels ;
int pitch ;
if ( ! SDL_LockTexture ( tex , NULL , ( void * * ) & pixels , & pitch ) ) {
sws_scale ( * img_convert_ctx , ( const uint8_t * const * ) frame - > data , frame - > linesize ,
0 , frame - > height , & pixels , & pitch ) ;
SDL_UnlockTexture ( tex ) ;
}
} else {
av_log ( NULL , AV_LOG_FATAL , " Cannot initialize the conversion context \n " ) ;
ret = - 1 ;
}
break ;
}
return ret ;
}
static void video_image_display ( VideoState * is )
{
Frame * vp ;
Frame * sp ;
Frame * sp = NULL ;
SDL_Rect rect ;
int i ;
vp = frame_queue_peek_last ( & is - > pictq ) ;
if ( vp - > bmp ) {
@ -950,36 +910,71 @@ static void video_image_display(VideoState *is)
sp = frame_queue_peek ( & is - > subpq ) ;
if ( vp - > pts > = sp - > pts + ( ( float ) sp - > sub . start_display_time / 1000 ) ) {
uint8_t * data [ 4 ] ;
int linesize [ 4 ] ;
SDL_LockYUVOverlay ( vp - > bmp ) ;
data [ 0 ] = vp - > bmp - > pixels [ 0 ] ;
data [ 1 ] = vp - > bmp - > pixels [ 2 ] ;
data [ 2 ] = vp - > bmp - > pixels [ 1 ] ;
linesize [ 0 ] = vp - > bmp - > pitches [ 0 ] ;
linesize [ 1 ] = vp - > bmp - > pitches [ 2 ] ;
linesize [ 2 ] = vp - > bmp - > pitches [ 1 ] ;
for ( i = 0 ; i < sp - > sub . num_rects ; i + + )
blend_subrect ( data , linesize , sp - > subrects [ i ] ,
vp - > bmp - > w , vp - > bmp - > h ) ;
SDL_UnlockYUVOverlay ( vp - > bmp ) ;
}
if ( ! sp - > uploaded ) {
uint8_t * pixels ;
int pitch ;
int i ;
if ( ! sp - > width | | ! sp - > height ) {
sp - > width = vp - > width ;
sp - > height = vp - > height ;
}
if ( realloc_texture ( & is - > sub_texture , SDL_PIXELFORMAT_ARGB8888 , sp - > width , sp - > height , SDL_BLENDMODE_BLEND , 1 ) < 0 )
return ;
for ( i = 0 ; i < sp - > sub . num_rects ; i + + ) {
AVSubtitleRect * sub_rect = sp - > sub . rects [ i ] ;
sub_rect - > x = av_clip ( sub_rect - > x , 0 , sp - > width ) ;
sub_rect - > y = av_clip ( sub_rect - > y , 0 , sp - > height ) ;
sub_rect - > w = av_clip ( sub_rect - > w , 0 , sp - > width - sub_rect - > x ) ;
sub_rect - > h = av_clip ( sub_rect - > h , 0 , sp - > height - sub_rect - > y ) ;
is - > sub_convert_ctx = sws_getCachedContext ( is - > sub_convert_ctx ,
sub_rect - > w , sub_rect - > h , AV_PIX_FMT_PAL8 ,
sub_rect - > w , sub_rect - > h , AV_PIX_FMT_BGRA ,
0 , NULL , NULL , NULL ) ;
if ( ! is - > sub_convert_ctx ) {
av_log ( NULL , AV_LOG_FATAL , " Cannot initialize the conversion context \n " ) ;
return ;
}
if ( ! SDL_LockTexture ( is - > sub_texture , ( SDL_Rect * ) sub_rect , ( void * * ) & pixels , & pitch ) ) {
sws_scale ( is - > sub_convert_ctx , ( const uint8_t * const * ) sub_rect - > data , sub_rect - > linesize ,
0 , sub_rect - > h , & pixels , & pitch ) ;
SDL_UnlockTexture ( is - > sub_texture ) ;
}
}
sp - > uploaded = 1 ;
}
} else
sp = NULL ;
}
}
calculate_display_rect ( & rect , is - > xleft , is - > ytop , is - > width , is - > height , vp - > width , vp - > height , vp - > sar ) ;
SDL_DisplayYUVOverlay ( vp - > bmp , & rect ) ;
if ( ! vp - > uploaded ) {
if ( upload_texture ( vp - > bmp , vp - > frame , & is - > img_convert_ctx ) < 0 )
return ;
vp - > uploaded = 1 ;
}
if ( rect . x ! = is - > last_display_rect . x | | rect . y ! = is - > last_display_rect . y | | rect . w ! = is - > last_display_rect . w | | rect . h ! = is - > last_display_rect . h | | is - > force_refresh ) {
int bgcolor = SDL_MapRGB ( screen - > format , 0x00 , 0x00 , 0x00 ) ;
fill_border ( is - > xleft , is - > ytop , is - > width , is - > height , rect . x , rect . y , rect . w , rect . h , bgcolor , 1 ) ;
is - > last_display_rect = rect ;
SDL_RenderCopy ( renderer , vp - > bmp , NULL , & rect ) ;
if ( sp ) {
# if USE_ONEPASS_SUBTITLE_RENDER
SDL_RenderCopy ( renderer , is - > sub_texture , NULL , & rect ) ;
# else
int i ;
double xratio = ( double ) rect . w / ( double ) sp - > width ;
double yratio = ( double ) rect . h / ( double ) sp - > height ;
for ( i = 0 ; i < sp - > sub . num_rects ; i + + ) {
SDL_Rect * sub_rect = ( SDL_Rect * ) sp - > sub . rects [ i ] ;
SDL_Rect target = { . x = rect . x + sub_rect - > x * xratio ,
. y = rect . y + sub_rect - > y * yratio ,
. w = sub_rect - > w * xratio ,
. h = sub_rect - > h * yratio } ;
SDL_RenderCopy ( renderer , is - > sub_texture , sub_rect , & target ) ;
}
# endif
}
}
}
@ -992,7 +987,7 @@ static inline int compute_mod(int a, int b)
static void video_audio_display ( VideoState * s )
{
int i , i_start , x , y1 , y , ys , delay , n , nb_display_channels ;
int ch , channels , h , h2 , bgcolor , fgcolor ;
int ch , channels , h , h2 ;
int64_t time_diff ;
int rdft_bits , nb_freq ;
@ -1042,13 +1037,8 @@ static void video_audio_display(VideoState *s)
i_start = s - > last_i_start ;
}
bgcolor = SDL_MapRGB ( screen - > format , 0x00 , 0x00 , 0x00 ) ;
if ( s - > show_mode = = SHOW_MODE_WAVES ) {
fill_rectangle ( screen ,
s - > xleft , s - > ytop , s - > width , s - > height ,
bgcolor , 0 ) ;
fgcolor = SDL_MapRGB ( screen - > format , 0xff , 0xff , 0xff ) ;
SDL_SetRenderDrawColor ( renderer , 255 , 255 , 255 , 255 ) ;
/* total height for one channel */
h = s - > height / nb_display_channels ;
@ -1065,25 +1055,23 @@ static void video_audio_display(VideoState *s)
} else {
ys = y1 ;
}
fill_rectangle ( screen ,
s - > xleft + x , ys , 1 , y ,
fgcolor , 0 ) ;
fill_rectangle ( s - > xleft + x , ys , 1 , y ) ;
i + = channels ;
if ( i > = SAMPLE_ARRAY_SIZE )
i - = SAMPLE_ARRAY_SIZE ;
}
}
fgcolor = SDL_MapRGB ( screen - > format , 0x00 , 0x00 , 0xff ) ;
SDL_SetRenderDrawColor ( renderer , 0 , 0 , 255 , 255 ) ;
for ( ch = 1 ; ch < nb_display_channels ; ch + + ) {
y = s - > ytop + ch * h ;
fill_rectangle ( screen ,
s - > xleft , y , s - > width , 1 ,
fgcolor , 0 ) ;
fill_rectangle ( s - > xleft , y , s - > width , 1 ) ;
}
SDL_UpdateRect ( screen , s - > xleft , s - > ytop , s - > width , s - > height ) ;
} else {
if ( realloc_texture ( & s - > vis_texture , SDL_PIXELFORMAT_ARGB8888 , s - > width , s - > height , SDL_BLENDMODE_NONE , 1 ) < 0 )
return ;
nb_display_channels = FFMIN ( nb_display_channels , 2 ) ;
if ( rdft_bits ! = s - > rdft_bits ) {
av_rdft_end ( s - > rdft ) ;
@ -1097,6 +1085,9 @@ static void video_audio_display(VideoState *s)
s - > show_mode = SHOW_MODE_WAVES ;
} else {
FFTSample * data [ 2 ] ;
SDL_Rect rect = { . x = s - > xpos , . y = 0 , . w = 1 , . h = s - > height } ;
uint32_t * pixels ;
int pitch ;
for ( ch = 0 ; ch < nb_display_channels ; ch + + ) {
data [ ch ] = s - > rdft_data + 2 * nb_freq * ch ;
i = i_start + ch ;
@ -1111,21 +1102,23 @@ static void video_audio_display(VideoState *s)
}
/* Least efficient way to do this, we should of course
* directly access it but it is more than fast enough . */
for ( y = 0 ; y < s - > height ; y + + ) {
double w = 1 / sqrt ( nb_freq ) ;
int a = sqrt ( w * hypot ( data [ 0 ] [ 2 * y + 0 ] , data [ 0 ] [ 2 * y + 1 ] ) ) ;
int b = ( nb_display_channels = = 2 ) ? sqrt ( w * hypot ( data [ 1 ] [ 2 * y + 0 ] , data [ 1 ] [ 2 * y + 1 ] ) )
: a ;
a = FFMIN ( a , 255 ) ;
b = FFMIN ( b , 255 ) ;
fgcolor = SDL_MapRGB ( screen - > format , a , b , ( a + b ) / 2 ) ;
fill_rectangle ( screen ,
s - > xpos , s - > height - y , 1 , 1 ,
fgcolor , 0 ) ;
if ( ! SDL_LockTexture ( s - > vis_texture , & rect , ( void * * ) & pixels , & pitch ) ) {
pitch > > = 2 ;
pixels + = pitch * s - > height ;
for ( y = 0 ; y < s - > height ; y + + ) {
double w = 1 / sqrt ( nb_freq ) ;
int a = sqrt ( w * sqrt ( data [ 0 ] [ 2 * y + 0 ] * data [ 0 ] [ 2 * y + 0 ] + data [ 0 ] [ 2 * y + 1 ] * data [ 0 ] [ 2 * y + 1 ] ) ) ;
int b = ( nb_display_channels = = 2 ) ? sqrt ( w * hypot ( data [ 1 ] [ 2 * y + 0 ] , data [ 1 ] [ 2 * y + 1 ] ) )
: a ;
a = FFMIN ( a , 255 ) ;
b = FFMIN ( b , 255 ) ;
pixels - = pitch ;
* pixels = ( a < < 16 ) + ( b < < 8 ) + ( ( a + b ) > > 1 ) ;
}
SDL_UnlockTexture ( s - > vis_texture ) ;
}
SDL_RenderCopy ( renderer , s - > vis_texture , NULL , NULL ) ;
}
SDL_UpdateRect ( screen , s - > xpos , s - > ytop , 1 , s - > height ) ;
if ( ! s - > paused )
s - > xpos + + ;
if ( s - > xpos > = s - > width )
@ -1215,11 +1208,13 @@ static void stream_close(VideoState *is)
frame_queue_destory ( & is - > sampq ) ;
frame_queue_destory ( & is - > subpq ) ;
SDL_DestroyCond ( is - > continue_read_thread ) ;
# if !CONFIG_AVFILTER
sws_freeContext ( is - > img_convert_ctx ) ;
# endif
sws_freeContext ( is - > sub_convert_ctx ) ;
av_free ( is - > filename ) ;
if ( is - > vis_texture )
SDL_DestroyTexture ( is - > vis_texture ) ;
if ( is - > sub_texture )
SDL_DestroyTexture ( is - > sub_texture ) ;
av_free ( is ) ;
}
@ -1228,6 +1223,10 @@ static void do_exit(VideoState *is)
if ( is ) {
stream_close ( is ) ;
}
if ( renderer )
SDL_DestroyRenderer ( renderer ) ;
if ( window )
SDL_DestroyWindow ( window ) ;
av_lockmgr_register ( NULL ) ;
uninit_opts ( ) ;
# if CONFIG_AVFILTER
@ -1254,42 +1253,48 @@ static void set_default_window_size(int width, int height, AVRational sar)
default_height = rect . h ;
}
static int video_open ( VideoState * is , int force_set_video_mode , Frame * vp )
static int video_open ( VideoState * is , Frame * vp )
{
int flags = SDL_HWSURFACE | SDL_ASYNCBLIT | SDL_HWACCEL ;
int w , h ;
if ( is_full_screen ) flags | = SDL_FULLSCREEN ;
else flags | = SDL_RESIZABLE ;
if ( vp & & vp - > width )
set_default_window_size ( vp - > width , vp - > height , vp - > sar ) ;
if ( is_full_screen & & fs_screen_width ) {
w = fs_screen_width ;
h = fs_screen_height ;
} else if ( ! is_full_screen & & screen_width ) {
if ( screen_width ) {
w = screen_width ;
h = screen_height ;
} else {
w = default_width ;
h = default_height ;
}
w = FFMIN ( 16383 , w ) ;
if ( screen & & is - > width = = screen - > w & & screen - > w = = w
& & is - > height = = screen - > h & & screen - > h = = h & & ! force_set_video_mode )
return 0 ;
screen = SDL_SetVideoMode ( w , h , 0 , flags ) ;
if ( ! screen ) {
if ( ! window ) {
int flags = SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE ;
if ( ! window_title )
window_title = input_filename ;
if ( is_full_screen )
flags | = SDL_WINDOW_FULLSCREEN_DESKTOP ;
window = SDL_CreateWindow ( window_title , SDL_WINDOWPOS_UNDEFINED , SDL_WINDOWPOS_UNDEFINED , w , h , flags ) ;
SDL_SetHint ( SDL_HINT_RENDER_SCALE_QUALITY , " linear " ) ;
if ( window ) {
SDL_RendererInfo info ;
renderer = SDL_CreateRenderer ( window , - 1 , SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC ) ;
if ( renderer ) {
if ( ! SDL_GetRendererInfo ( renderer , & info ) )
av_log ( NULL , AV_LOG_VERBOSE , " Initialized %s renderer. \n " , info . name ) ;
}
}
} else {
SDL_SetWindowSize ( window , w , h ) ;
}
if ( ! window | | ! renderer ) {
av_log ( NULL , AV_LOG_FATAL , " SDL: could not set video mode - exiting \n " ) ;
do_exit ( is ) ;
}
if ( ! window_title )
window_title = input_filename ;
SDL_WM_SetCaption ( window_title , window_title ) ;
is - > width = screen - > w ;
is - > height = screen - > h ;
is - > width = w ;
is - > height = h ;
return 0 ;
}
@ -1297,12 +1302,16 @@ static int video_open(VideoState *is, int force_set_video_mode, Frame *vp)
/* display the current picture, if any */
static void video_display ( VideoState * is )
{
if ( ! screen )
video_open ( is , 0 , NULL ) ;
if ( ! window )
video_open ( is , NULL ) ;
SDL_SetRenderDrawColor ( renderer , 0 , 0 , 0 , 255 ) ;
SDL_RenderClear ( renderer ) ;
if ( is - > audio_st & & is - > show_mode ! = SHOW_MODE_VIDEO )
video_audio_display ( is ) ;
else if ( is - > video_st )
video_image_display ( is ) ;
SDL_RenderPresent ( renderer ) ;
}
static double get_clock ( Clock * c )
@ -1587,6 +1596,20 @@ retry:
| | ( is - > vidclk . pts > ( sp - > pts + ( ( float ) sp - > sub . end_display_time / 1000 ) ) )
| | ( sp2 & & is - > vidclk . pts > ( sp2 - > pts + ( ( float ) sp2 - > sub . start_display_time / 1000 ) ) ) )
{
if ( sp - > uploaded ) {
int i ;
for ( i = 0 ; i < sp - > sub . num_rects ; i + + ) {
AVSubtitleRect * sub_rect = sp - > sub . rects [ i ] ;
uint8_t * pixels ;
int pitch , j ;
if ( ! SDL_LockTexture ( is - > sub_texture , ( SDL_Rect * ) sub_rect , ( void * * ) & pixels , & pitch ) ) {
for ( j = 0 ; j < sub_rect - > h ; j + + , pixels + = pitch )
memset ( pixels , 0 , sub_rect - > w < < 2 ) ;
SDL_UnlockTexture ( is - > sub_texture ) ;
}
}
}
frame_queue_next ( & is - > subpq ) ;
} else {
break ;
@ -1652,19 +1675,18 @@ display:
static void alloc_picture ( VideoState * is )
{
Frame * vp ;
int64_t bufferdiff ;
int sdl_format ;
vp = & is - > pictq . queue [ is - > pictq . windex ] ;
free_picture ( vp ) ;
video_open ( is , vp ) ;
video_open ( is , 0 , vp ) ;
if ( vp - > format = = AV_PIX_FMT_YUV420P )
sdl_format = SDL_PIXELFORMAT_YV12 ;
else
sdl_format = SDL_PIXELFORMAT_ARGB8888 ;
vp - > bmp = SDL_CreateYUVOverlay ( vp - > width , vp - > height ,
SDL_YV12_OVERLAY ,
screen ) ;
bufferdiff = vp - > bmp ? FFMAX ( vp - > bmp - > pixels [ 0 ] , vp - > bmp - > pixels [ 1 ] ) - FFMIN ( vp - > bmp - > pixels [ 0 ] , vp - > bmp - > pixels [ 1 ] ) : 0 ;
if ( ! vp - > bmp | | vp - > bmp - > pitches [ 0 ] < vp - > width | | bufferdiff < ( int64_t ) vp - > height * vp - > bmp - > pitches [ 0 ] ) {
if ( realloc_texture ( & vp - > bmp , sdl_format , vp - > width , vp - > height , SDL_BLENDMODE_NONE , 0 ) < 0 ) {
/* SDL allocates a buffer smaller than requested if the video
* overlay hardware is unable to support the requested size . */
av_log ( NULL , AV_LOG_FATAL ,
@ -1680,24 +1702,6 @@ static void alloc_picture(VideoState *is)
SDL_UnlockMutex ( is - > pictq . mutex ) ;
}
static void duplicate_right_border_pixels ( SDL_Overlay * bmp ) {
int i , width , height ;
Uint8 * p , * maxp ;
for ( i = 0 ; i < 3 ; i + + ) {
width = bmp - > w ;
height = bmp - > h ;
if ( i > 0 ) {
width > > = 1 ;
height > > = 1 ;
}
if ( bmp - > pitches [ i ] > width ) {
maxp = bmp - > pixels [ i ] + bmp - > pitches [ i ] * height - 1 ;
for ( p = bmp - > pixels [ i ] + width - 1 ; p < maxp ; p + = bmp - > pitches [ i ] )
* ( p + 1 ) = * p ;
}
}
}
static int queue_picture ( VideoState * is , AVFrame * src_frame , double pts , double duration , int64_t pos , int serial )
{
Frame * vp ;
@ -1711,17 +1715,19 @@ static int queue_picture(VideoState *is, AVFrame *src_frame, double pts, double
return - 1 ;
vp - > sar = src_frame - > sample_aspect_ratio ;
vp - > uploaded = 0 ;
/* alloc or resize hardware picture buffer */
if ( ! vp - > bmp | | vp - > reallocate | | ! vp - > allocated | |
if ( ! vp - > bmp | | ! vp - > allocated | |
vp - > width ! = src_frame - > width | |
vp - > height ! = src_frame - > height ) {
vp - > height ! = src_frame - > height | |
vp - > format ! = src_frame - > format ) {
SDL_Event event ;
vp - > allocated = 0 ;
vp - > reallocate = 0 ;
vp - > allocated = 0 ;
vp - > width = src_frame - > width ;
vp - > height = src_frame - > height ;
vp - > format = src_frame - > format ;
/* the allocation must be done in the main thread to avoid
locking problems . */
@ -1735,7 +1741,7 @@ static int queue_picture(VideoState *is, AVFrame *src_frame, double pts, double
SDL_CondWait ( is - > pictq . cond , is - > pictq . mutex ) ;
}
/* if the queue is aborted, we have to pop the pending ALLOC event or wait for the allocation to complete */
if ( is - > videoq . abort_request & & SDL_PeepEvents ( & event , 1 , SDL_GETEVENT , SDL_EVENTMASK ( FF_ALLOC_EVENT ) ) ! = 1 ) {
if ( is - > videoq . abort_request & & SDL_PeepEvents ( & event , 1 , SDL_GETEVENT , FF_ALLOC_EVENT , FF_ALLOC_EVENT ) ! = 1 ) {
while ( ! vp - > allocated & & ! is - > abort_request ) {
SDL_CondWait ( is - > pictq . cond , is - > pictq . mutex ) ;
}
@ -1748,58 +1754,12 @@ static int queue_picture(VideoState *is, AVFrame *src_frame, double pts, double
/* if the frame is not skipped, then display it */
if ( vp - > bmp ) {
uint8_t * data [ 4 ] ;
int linesize [ 4 ] ;
/* get a pointer on the bitmap */
SDL_LockYUVOverlay ( vp - > bmp ) ;
data [ 0 ] = vp - > bmp - > pixels [ 0 ] ;
data [ 1 ] = vp - > bmp - > pixels [ 2 ] ;
data [ 2 ] = vp - > bmp - > pixels [ 1 ] ;
linesize [ 0 ] = vp - > bmp - > pitches [ 0 ] ;
linesize [ 1 ] = vp - > bmp - > pitches [ 2 ] ;
linesize [ 2 ] = vp - > bmp - > pitches [ 1 ] ;
# if CONFIG_AVFILTER
// FIXME use direct rendering
av_image_copy ( data , linesize , ( const uint8_t * * ) src_frame - > data , src_frame - > linesize ,
src_frame - > format , vp - > width , vp - > height ) ;
# else
{
AVDictionaryEntry * e = av_dict_get ( sws_dict , " sws_flags " , NULL , 0 ) ;
if ( e ) {
const AVClass * class = sws_get_class ( ) ;
const AVOption * o = av_opt_find ( & class , " sws_flags " , NULL , 0 ,
AV_OPT_SEARCH_FAKE_OBJ ) ;
int ret = av_opt_eval_flags ( & class , o , e - > value , & sws_flags ) ;
if ( ret < 0 )
exit ( 1 ) ;
}
}
is - > img_convert_ctx = sws_getCachedContext ( is - > img_convert_ctx ,
vp - > width , vp - > height , src_frame - > format , vp - > width , vp - > height ,
AV_PIX_FMT_YUV420P , sws_flags , NULL , NULL , NULL ) ;
if ( ! is - > img_convert_ctx ) {
av_log ( NULL , AV_LOG_FATAL , " Cannot initialize the conversion context \n " ) ;
exit ( 1 ) ;
}
sws_scale ( is - > img_convert_ctx , src_frame - > data , src_frame - > linesize ,
0 , vp - > height , data , linesize ) ;
# endif
/* workaround SDL PITCH_WORKAROUND */
duplicate_right_border_pixels ( vp - > bmp ) ;
/* update the bitmap content */
SDL_UnlockYUVOverlay ( vp - > bmp ) ;
vp - > pts = pts ;
vp - > duration = duration ;
vp - > pos = pos ;
vp - > serial = serial ;
/* now we can update the picture count */
av_frame_move_ref ( vp - > frame , src_frame ) ;
frame_queue_push ( & is - > pictq ) ;
}
return 0 ;
@ -1887,7 +1847,7 @@ fail:
static int configure_video_filters ( AVFilterGraph * graph , VideoState * is , const char * vfilters , AVFrame * frame )
{
static const enum AVPixelFormat pix_fmts [ ] = { AV_PIX_FMT_YUV420P , AV_PIX_FMT_NONE } ;
static const enum AVPixelFormat pix_fmts [ ] = { AV_PIX_FMT_YUV420P , AV_PIX_FMT_BGRA , AV_PIX_FMT_ NONE } ;
char sws_flags_str [ 512 ] = " " ;
char buffersrc_args [ 256 ] ;
int ret ;
@ -1950,10 +1910,6 @@ static int configure_video_filters(AVFilterGraph *graph, VideoState *is, const c
last_filter = filt_ctx ; \
} while ( 0 )
/* SDL YUV code is not handling odd width/height for some driver
* combinations , therefore we crop the picture to an even width / height . */
INSERT_FILT ( " crop " , " floor(in_w/2)*2:floor(in_h/2)*2 " ) ;
if ( autorotate ) {
double theta = get_rotation ( is - > video_st ) ;
@ -2148,7 +2104,7 @@ static int audio_thread(void *arg)
static int decoder_start ( Decoder * d , int ( * fn ) ( void * ) , void * arg )
{
packet_queue_start ( d - > queue ) ;
d - > decoder_tid = SDL_CreateThread ( fn , arg ) ;
d - > decoder_tid = SDL_CreateThread ( fn , " decoder " , arg ) ;
if ( ! d - > decoder_tid ) {
av_log ( NULL , AV_LOG_ERROR , " SDL_CreateThread(): %s \n " , SDL_GetError ( ) ) ;
return AVERROR ( ENOMEM ) ;
@ -2268,10 +2224,10 @@ static int video_thread(void *arg)
static int subtitle_thread ( void * arg )
{
VideoState * is = arg ;
AVCodecParameters * codecpar = is - > subtitle_st - > codecpar ;
Frame * sp ;
int got_subtitle ;
double pts ;
int i ;
for ( ; ; ) {
if ( ! ( sp = frame_queue_peek_writable ( & is - > subpq ) ) )
@ -2287,42 +2243,9 @@ static int subtitle_thread(void *arg)
pts = sp - > sub . pts / ( double ) AV_TIME_BASE ;
sp - > pts = pts ;
sp - > serial = is - > subdec . pkt_serial ;
if ( ! ( sp - > subrects = av_mallocz_array ( sp - > sub . num_rects , sizeof ( AVSubtitleRect * ) ) ) ) {
av_log ( NULL , AV_LOG_FATAL , " Cannot allocate subrects \n " ) ;
exit ( 1 ) ;
}
for ( i = 0 ; i < sp - > sub . num_rects ; i + + )
{
int in_w = sp - > sub . rects [ i ] - > w ;
int in_h = sp - > sub . rects [ i ] - > h ;
int subw = is - > subdec . avctx - > width ? is - > subdec . avctx - > width : is - > viddec_width ;
int subh = is - > subdec . avctx - > height ? is - > subdec . avctx - > height : is - > viddec_height ;
int out_w = is - > viddec_width ? in_w * is - > viddec_width / subw : in_w ;
int out_h = is - > viddec_height ? in_h * is - > viddec_height / subh : in_h ;
if ( ! ( sp - > subrects [ i ] = av_mallocz ( sizeof ( AVSubtitleRect ) ) ) | |
av_image_alloc ( sp - > subrects [ i ] - > data , sp - > subrects [ i ] - > linesize , out_w , out_h , AV_PIX_FMT_YUVA420P , 16 ) < 0 ) {
av_log ( NULL , AV_LOG_FATAL , " Cannot allocate subtitle data \n " ) ;
exit ( 1 ) ;
}
is - > sub_convert_ctx = sws_getCachedContext ( is - > sub_convert_ctx ,
in_w , in_h , AV_PIX_FMT_PAL8 , out_w , out_h ,
AV_PIX_FMT_YUVA420P , sws_flags , NULL , NULL , NULL ) ;
if ( ! is - > sub_convert_ctx ) {
av_log ( NULL , AV_LOG_FATAL , " Cannot initialize the sub conversion context \n " ) ;
exit ( 1 ) ;
}
sws_scale ( is - > sub_convert_ctx ,
( void * ) sp - > sub . rects [ i ] - > data , sp - > sub . rects [ i ] - > linesize ,
0 , in_h , sp - > subrects [ i ] - > data , sp - > subrects [ i ] - > linesize ) ;
sp - > subrects [ i ] - > w = out_w ;
sp - > subrects [ i ] - > h = out_h ;
sp - > subrects [ i ] - > x = sp - > sub . rects [ i ] - > x * out_w / in_w ;
sp - > subrects [ i ] - > y = sp - > sub . rects [ i ] - > y * out_h / in_h ;
}
sp - > width = codecpar - > width ;
sp - > height = codecpar - > height ;
sp - > uploaded = 0 ;
/* now we can update the picture count */
frame_queue_push ( & is - > subpq ) ;
@ -3185,7 +3108,7 @@ static VideoState *stream_open(const char *filename, AVInputFormat *iformat)
is - > audio_volume = SDL_MIX_MAXVOLUME ;
is - > muted = 0 ;
is - > av_sync_type = av_sync_type ;
is - > read_tid = SDL_CreateThread ( read_thread , is ) ;
is - > read_tid = SDL_CreateThread ( read_thread , " read_thread " , is ) ;
if ( ! is - > read_tid ) {
av_log ( NULL , AV_LOG_FATAL , " SDL_CreateThread(): %s \n " , SDL_GetError ( ) ) ;
fail :
@ -3276,27 +3199,17 @@ static void stream_cycle_channel(VideoState *is, int codec_type)
static void toggle_full_screen ( VideoState * is )
{
# if defined(__APPLE__) && SDL_VERSION_ATLEAST(1, 2, 14)
/* OS X needs to reallocate the SDL overlays */
int i ;
for ( i = 0 ; i < VIDEO_PICTURE_QUEUE_SIZE ; i + + )
is - > pictq . queue [ i ] . reallocate = 1 ;
# endif
is_full_screen = ! is_full_screen ;
video_open ( is , 1 , NULL ) ;
SDL_SetWindowFullscreen ( window , is_full_screen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0 ) ;
}
static void toggle_audio_display ( VideoState * is )
{
int bgcolor = SDL_MapRGB ( screen - > format , 0x00 , 0x00 , 0x00 ) ;
int next = is - > show_mode ;
do {
next = ( next + 1 ) % SHOW_MODE_NB ;
} while ( next ! = is - > show_mode & & ( next = = SHOW_MODE_VIDEO & & ! is - > video_st | | next ! = SHOW_MODE_VIDEO & & ! is - > audio_st ) ) ;
if ( is - > show_mode ! = next ) {
fill_rectangle ( screen ,
is - > xleft , is - > ytop , is - > width , is - > height ,
bgcolor , 1 ) ;
is - > force_refresh = 1 ;
is - > show_mode = next ;
}
@ -3305,7 +3218,7 @@ static void toggle_audio_display(VideoState *is)
static void refresh_loop_wait_event ( VideoState * is , SDL_Event * event ) {
double remaining_time = 0.0 ;
SDL_PumpEvents ( ) ;
while ( ! SDL_PeepEvents ( event , 1 , SDL_GETEVENT , SDL_ALLEVENTS ) ) {
while ( ! SDL_PeepEvents ( event , 1 , SDL_GETEVENT , SDL_FIRSTEVENT , SDL_LASTEVENT ) ) {
if ( ! cursor_hidden & & av_gettime_relative ( ) - cursor_last_shown > CURSOR_HIDE_DELAY ) {
SDL_ShowCursor ( 0 ) ;
cursor_hidden = 1 ;
@ -3469,9 +3382,6 @@ static void event_loop(VideoState *cur_stream)
break ;
}
break ;
case SDL_VIDEOEXPOSE :
cur_stream - > force_refresh = 1 ;
break ;
case SDL_MOUSEBUTTONDOWN :
if ( exit_on_mousedown ) {
do_exit ( cur_stream ) ;
@ -3527,16 +3437,18 @@ static void event_loop(VideoState *cur_stream)
stream_seek ( cur_stream , ts , 0 , 0 ) ;
}
break ;
case SDL_VIDEORESIZE :
screen = SDL_SetVideoMode ( FFMIN ( 16383 , event . resize . w ) , event . resize . h , 0 ,
SDL_HWSURFACE | ( is_full_screen ? SDL_FULLSCREEN : SDL_RESIZABLE ) | SDL_ASYNCBLIT | SDL_HWACCEL ) ;
if ( ! screen ) {
av_log ( NULL , AV_LOG_FATAL , " Failed to set video mode \n " ) ;
do_exit ( cur_stream ) ;
}
screen_width = cur_stream - > width = screen - > w ;
screen_height = cur_stream - > height = screen - > h ;
cur_stream - > force_refresh = 1 ;
case SDL_WINDOWEVENT :
switch ( event . window . event ) {
case SDL_WINDOWEVENT_RESIZED :
screen_width = cur_stream - > width = event . window . data1 ;
screen_height = cur_stream - > height = event . window . data2 ;
if ( cur_stream - > vis_texture ) {
SDL_DestroyTexture ( cur_stream - > vis_texture ) ;
cur_stream - > vis_texture = NULL ;
}
case SDL_WINDOWEVENT_EXPOSED :
cur_stream - > force_refresh = 1 ;
}
break ;
case SDL_QUIT :
case FF_QUIT_EVENT :
@ -3773,8 +3685,6 @@ int main(int argc, char **argv)
{
int flags ;
VideoState * is ;
char dummy_videodriver [ ] = " SDL_VIDEODRIVER=dummy " ;
char alsa_bufsize [ ] = " SDL_AUDIO_ALSA_SET_BUFFER_SIZE=1 " ;
init_dynload ( ) ;
@ -3818,31 +3728,19 @@ int main(int argc, char **argv)
/* Try to work around an occasional ALSA buffer underflow issue when the
* period size is NPOT due to ALSA resampling by forcing the buffer size . */
if ( ! SDL_getenv ( " SDL_AUDIO_ALSA_SET_BUFFER_SIZE " ) )
SDL_putenv ( alsa_bufsize ) ;
SDL_setenv ( " SDL_AUDIO_ALSA_SET_BUFFER_SIZE " , " 1 " , 1 ) ;
}
if ( display_disable )
SDL_putenv ( dummy_videodriver ) ; /* For the event queue, we always need a video driver. */
# if !defined(_WIN32) && !defined(__APPLE__)
flags | = SDL_INIT_EVENTTHREAD ; /* Not supported on Windows or Mac OS X */
# endif
flags & = ~ SDL_INIT_VIDEO ;
if ( SDL_Init ( flags ) ) {
av_log ( NULL , AV_LOG_FATAL , " Could not initialize SDL - %s \n " , SDL_GetError ( ) ) ;
av_log ( NULL , AV_LOG_FATAL , " (Did you set the DISPLAY variable?) \n " ) ;
exit ( 1 ) ;
}
if ( ! display_disable ) {
const SDL_VideoInfo * vi = SDL_GetVideoInfo ( ) ;
fs_screen_width = vi - > current_w ;
fs_screen_height = vi - > current_h ;
}
SDL_EventState ( SDL_ACTIVEEVENT , SDL_IGNORE ) ;
SDL_EventState ( SDL_SYSWMEVENT , SDL_IGNORE ) ;
SDL_EventState ( SDL_USEREVENT , SDL_IGNORE ) ;
SDL_EnableKeyRepeat ( SDL_DEFAULT_REPEAT_DELAY , SDL_DEFAULT_REPEAT_INTERVAL ) ;
if ( av_lockmgr_register ( lockmgr ) ) {
av_log ( NULL , AV_LOG_FATAL , " Could not initialize lock manager! \n " ) ;
do_exit ( NULL ) ;