}
#endif
+#undef exit
+
//#define DEBUG_SYNC
#define MAX_VIDEOQ_SIZE (5 * 256 * 1024)
SDL_mutex *pictq_mutex;
SDL_cond *pictq_cond;
- SDL_mutex *video_decoder_mutex;
- SDL_mutex *audio_decoder_mutex;
- SDL_mutex *subtitle_decoder_mutex;
-
// QETimer *video_timer;
char filename[1024];
int width, height, xleft, ytop;
static const char *input_filename;
static int fs_screen_width;
static int fs_screen_height;
-static int screen_width = 640;
-static int screen_height = 480;
+static int screen_width = 0;
+static int screen_height = 0;
+static int frame_width = 0;
+static int frame_height = 0;
+static enum PixelFormat frame_pix_fmt = PIX_FMT_NONE;
static int audio_disable;
static int video_disable;
+static int wanted_audio_stream= 0;
static int seek_by_bytes;
static int display_disable;
static int show_status;
static enum AVDiscard skip_loop_filter= AVDISCARD_DEFAULT;
static int error_resilience = FF_ER_CAREFUL;
static int error_concealment = 3;
+static int decoder_reorder_pts= 0;
/* current context */
static int is_full_screen;
static VideoState *cur_stream;
static int64_t audio_callback_time;
+AVPacket flush_pkt;
+
#define FF_ALLOC_EVENT (SDL_USEREVENT)
#define FF_REFRESH_EVENT (SDL_USEREVENT + 1)
#define FF_QUIT_EVENT (SDL_USEREVENT + 2)
AVPacketList *pkt1;
/* duplicate the packet */
- if (av_dup_packet(pkt) < 0)
+ if (pkt!=&flush_pkt && av_dup_packet(pkt) < 0)
return -1;
pkt1 = av_malloc(sizeof(AVPacketList));
is->no_background = 0;
}
rect.x = is->xleft + x;
- rect.y = is->xleft + y;
+ rect.y = is->ytop + y;
rect.w = width;
rect.h = height;
SDL_DisplayYUVOverlay(vp->bmp, &rect);
delay -= s->width / 2;
if (delay < s->width)
delay = s->width;
- i_start = compute_mod(s->sample_array_index - delay * channels, SAMPLE_ARRAY_SIZE);
+
+ i_start= x = compute_mod(s->sample_array_index - delay * channels, SAMPLE_ARRAY_SIZE);
+
+ h= INT_MIN;
+ for(i=0; i<1000; i+=channels){
+ int idx= (SAMPLE_ARRAY_SIZE + x - i) % SAMPLE_ARRAY_SIZE;
+ int a= s->sample_array[idx];
+ int b= s->sample_array[(idx + 4*channels)%SAMPLE_ARRAY_SIZE];
+ int c= s->sample_array[(idx + 5*channels)%SAMPLE_ARRAY_SIZE];
+ int d= s->sample_array[(idx + 9*channels)%SAMPLE_ARRAY_SIZE];
+ int score= a-d;
+ if(h<score && (b^c)<0){
+ h= score;
+ i_start= idx;
+ }
+ }
+
s->last_i_start = i_start;
} else {
i_start = s->last_i_start;
SDL_UpdateRect(screen, s->xleft, s->ytop, s->width, s->height);
}
+static int video_open(VideoState *is){
+ int flags = SDL_HWSURFACE|SDL_ASYNCBLIT|SDL_HWACCEL;
+ int w,h;
+
+ if(is_full_screen) flags |= SDL_FULLSCREEN;
+ else flags |= SDL_RESIZABLE;
+
+ if (is_full_screen && fs_screen_width) {
+ w = fs_screen_width;
+ h = fs_screen_height;
+ } else if(!is_full_screen && screen_width){
+ w = screen_width;
+ h = screen_height;
+ }else if (is->video_st && is->video_st->codec->width){
+ w = is->video_st->codec->width;
+ h = is->video_st->codec->height;
+ } else {
+ w = 640;
+ h = 480;
+ }
+#ifndef CONFIG_DARWIN
+ screen = SDL_SetVideoMode(w, h, 0, flags);
+#else
+ /* setting bits_per_pixel = 0 or 32 causes blank video on OS X */
+ screen = SDL_SetVideoMode(w, h, 24, flags);
+#endif
+ if (!screen) {
+ fprintf(stderr, "SDL: could not set video mode - exiting\n");
+ return -1;
+ }
+ SDL_WM_SetCaption("FFplay", "FFplay");
+
+ is->width = screen->w;
+ is->height = screen->h;
+
+ return 0;
+}
+
/* display the current picture, if any */
static void video_display(VideoState *is)
{
+ if(!screen)
+ video_open(cur_stream);
if (is->audio_st && is->show_audio)
video_audio_display(is);
else if (is->video_st)
static void stream_pause(VideoState *is)
{
is->paused = !is->paused;
- if (is->paused) {
+ if (!is->paused) {
is->video_current_pts = get_video_clock(is);
+ is->frame_timer += (av_gettime() - is->video_current_pts_time) / 1000000.0;
}
}
case PIX_FMT_YUV420P:
case PIX_FMT_YUV422P:
case PIX_FMT_YUV444P:
- case PIX_FMT_YUV422:
+ case PIX_FMT_YUYV422:
case PIX_FMT_YUV410P:
case PIX_FMT_YUV411P:
is_yuv = 1;
return queue_picture(is, src_frame, pts);
}
+static uint64_t global_video_pkt_pts= AV_NOPTS_VALUE;
+
+static int my_get_buffer(struct AVCodecContext *c, AVFrame *pic){
+ int ret= avcodec_default_get_buffer(c, pic);
+ uint64_t *pts= av_malloc(sizeof(uint64_t));
+ *pts= global_video_pkt_pts;
+ pic->opaque= pts;
+ return ret;
+}
+
+static void my_release_buffer(struct AVCodecContext *c, AVFrame *pic){
+ if(pic) av_freep(&pic->opaque);
+ avcodec_default_release_buffer(c, pic);
+}
+
static int video_thread(void *arg)
{
VideoState *is = arg;
}
if (packet_queue_get(&is->videoq, pkt, 1) < 0)
break;
+
+ if(pkt->data == flush_pkt.data){
+ avcodec_flush_buffers(is->video_st->codec);
+ continue;
+ }
+
/* NOTE: ipts is the PTS of the _first_ picture beginning in
this packet, if any */
- pts = 0;
- if (pkt->dts != AV_NOPTS_VALUE)
- pts = av_q2d(is->video_st->time_base)*pkt->dts;
-
- SDL_LockMutex(is->video_decoder_mutex);
- len1 = avcodec_decode_video(is->video_st->codec,
- frame, &got_picture,
- pkt->data, pkt->size);
- SDL_UnlockMutex(is->video_decoder_mutex);
+ global_video_pkt_pts= pkt->pts;
+ len1 = avcodec_decode_video(is->video_st->codec,
+ frame, &got_picture,
+ pkt->data, pkt->size);
+
+ if( (decoder_reorder_pts || pkt->dts == AV_NOPTS_VALUE)
+ && frame->opaque && *(uint64_t*)frame->opaque != AV_NOPTS_VALUE)
+ pts= *(uint64_t*)frame->opaque;
+ else if(pkt->dts != AV_NOPTS_VALUE)
+ pts= pkt->dts;
+ else
+ pts= 0;
+ pts *= av_q2d(is->video_st->time_base);
+
// if (len1 < 0)
// break;
- if (got_picture) {
- if (output_picture2(is, frame, pts) < 0)
- goto the_end;
- }
+ if (got_picture) {
+ if (output_picture2(is, frame, pts) < 0)
+ goto the_end;
+ }
av_free_packet(pkt);
if (step)
if (cur_stream)
if (packet_queue_get(&is->subtitleq, pkt, 1) < 0)
break;
+ if(pkt->data == flush_pkt.data){
+ avcodec_flush_buffers(is->subtitle_st->codec);
+ continue;
+ }
SDL_LockMutex(is->subpq_mutex);
while (is->subpq_size >= SUBPICTURE_QUEUE_SIZE &&
!is->subtitleq.abort_request) {
if (pkt->pts != AV_NOPTS_VALUE)
pts = av_q2d(is->subtitle_st->time_base)*pkt->pts;
- SDL_LockMutex(is->subtitle_decoder_mutex);
len1 = avcodec_decode_subtitle(is->subtitle_st->codec,
&sp->sub, &got_subtitle,
pkt->data, pkt->size);
- SDL_UnlockMutex(is->subtitle_decoder_mutex);
// if (len1 < 0)
// break;
if (got_subtitle && sp->sub.format == 0) {
}
/* decode one audio frame and returns its uncompressed size */
-static int audio_decode_frame(VideoState *is, uint8_t *audio_buf, double *pts_ptr)
+static int audio_decode_frame(VideoState *is, uint8_t *audio_buf, int buf_size, double *pts_ptr)
{
AVPacket *pkt = &is->audio_pkt;
int n, len1, data_size;
for(;;) {
/* NOTE: the audio packet can contain several frames */
while (is->audio_pkt_size > 0) {
- SDL_LockMutex(is->audio_decoder_mutex);
- len1 = avcodec_decode_audio(is->audio_st->codec,
+ data_size = buf_size;
+ len1 = avcodec_decode_audio2(is->audio_st->codec,
(int16_t *)audio_buf, &data_size,
is->audio_pkt_data, is->audio_pkt_size);
- SDL_UnlockMutex(is->audio_decoder_mutex);
if (len1 < 0) {
/* if error, we skip the frame */
is->audio_pkt_size = 0;
/* read next packet */
if (packet_queue_get(&is->audioq, pkt, 1) < 0)
return -1;
+ if(pkt->data == flush_pkt.data){
+ avcodec_flush_buffers(is->audio_st->codec);
+ continue;
+ }
+
is->audio_pkt_data = pkt->data;
is->audio_pkt_size = pkt->size;
cannot have a precise information */
static int audio_write_get_buf_size(VideoState *is)
{
- return is->audio_hw_buf_size - is->audio_buf_index;
+ return is->audio_buf_size - is->audio_buf_index;
}
while (len > 0) {
if (is->audio_buf_index >= is->audio_buf_size) {
- audio_size = audio_decode_frame(is, is->audio_buf, &pts);
+ audio_size = audio_decode_frame(is, is->audio_buf, sizeof(is->audio_buf), &pts);
if (audio_size < 0) {
/* if error, just output silence */
is->audio_buf_size = 1024;
}
}
-
/* open a given stream. Return 0 if OK */
static int stream_component_open(VideoState *is, int stream_index)
{
if (!codec ||
avcodec_open(enc, codec) < 0)
return -1;
-#if defined(HAVE_THREADS)
if(thread_count>1)
avcodec_thread_init(enc, thread_count);
-#endif
enc->thread_count= thread_count;
switch(enc->codec_type) {
case CODEC_TYPE_AUDIO:
packet_queue_init(&is->videoq);
is->video_tid = SDL_CreateThread(video_thread, is);
+
+ enc-> get_buffer= my_get_buffer;
+ enc->release_buffer= my_release_buffer;
break;
case CODEC_TYPE_SUBTITLE:
is->subtitle_stream = stream_index;
ap->initial_pause = 1; /* we force a pause when starting an RTSP
stream */
+ ap->width = frame_width;
+ ap->height= frame_height;
+ ap->time_base= (AVRational){1, 25};
+ ap->pix_fmt = frame_pix_fmt;
+
err = av_open_input_file(&ic, is->filename, is->iformat, 0, ap);
if (err < 0) {
print_error(is->filename, err);
AVCodecContext *enc = ic->streams[i]->codec;
switch(enc->codec_type) {
case CODEC_TYPE_AUDIO:
- if (audio_index < 0 && !audio_disable)
+ if ((audio_index < 0 || wanted_audio_stream-- > 0) && !audio_disable)
audio_index = i;
break;
case CODEC_TYPE_VIDEO:
}
#endif
if (is->seek_req) {
- /* XXX: must lock decoder threads */
- SDL_LockMutex(is->video_decoder_mutex);
- SDL_LockMutex(is->audio_decoder_mutex);
- SDL_LockMutex(is->subtitle_decoder_mutex);
- ret = av_seek_frame(is->ic, -1, is->seek_pos, is->seek_flags);
+ int stream_index= -1;
+ int64_t seek_target= is->seek_pos;
+
+ if (is-> video_stream >= 0) stream_index= is-> video_stream;
+ else if(is-> audio_stream >= 0) stream_index= is-> audio_stream;
+ else if(is->subtitle_stream >= 0) stream_index= is->subtitle_stream;
+
+ if(stream_index>=0){
+ seek_target= av_rescale_q(seek_target, AV_TIME_BASE_Q, ic->streams[stream_index]->time_base);
+ }
+
+ ret = av_seek_frame(is->ic, stream_index, seek_target, is->seek_flags);
if (ret < 0) {
fprintf(stderr, "%s: error while seeking\n", is->ic->filename);
}else{
if (is->audio_stream >= 0) {
packet_queue_flush(&is->audioq);
- avcodec_flush_buffers(ic->streams[audio_index]->codec);
+ packet_queue_put(&is->audioq, &flush_pkt);
}
if (is->subtitle_stream >= 0) {
packet_queue_flush(&is->subtitleq);
+ packet_queue_put(&is->subtitleq, &flush_pkt);
}
if (is->video_stream >= 0) {
packet_queue_flush(&is->videoq);
- avcodec_flush_buffers(ic->streams[video_index]->codec);
+ packet_queue_put(&is->videoq, &flush_pkt);
}
}
- SDL_UnlockMutex(is->subtitle_decoder_mutex);
- SDL_UnlockMutex(is->audio_decoder_mutex);
- SDL_UnlockMutex(is->video_decoder_mutex);
is->seek_req = 0;
}
return NULL;
pstrcpy(is->filename, sizeof(is->filename), filename);
is->iformat = iformat;
- if (screen) {
- is->width = screen->w;
- is->height = screen->h;
- }
is->ytop = 0;
is->xleft = 0;
is->subpq_mutex = SDL_CreateMutex();
is->subpq_cond = SDL_CreateCond();
- is->subtitle_decoder_mutex = SDL_CreateMutex();
- is->audio_decoder_mutex = SDL_CreateMutex();
- is->video_decoder_mutex = SDL_CreateMutex();
-
/* add the refresh timer to draw the picture */
schedule_refresh(is, 40);
SDL_DestroyCond(is->pictq_cond);
SDL_DestroyMutex(is->subpq_mutex);
SDL_DestroyCond(is->subpq_cond);
- SDL_DestroyMutex(is->subtitle_decoder_mutex);
- SDL_DestroyMutex(is->audio_decoder_mutex);
- SDL_DestroyMutex(is->video_decoder_mutex);
}
static void stream_cycle_channel(VideoState *is, int codec_type)
static void toggle_full_screen(void)
{
- int w, h, flags;
is_full_screen = !is_full_screen;
if (!fs_screen_width) {
/* use default SDL method */
- SDL_WM_ToggleFullScreen(screen);
- } else {
- /* use the recorded resolution */
- flags = SDL_HWSURFACE|SDL_ASYNCBLIT|SDL_HWACCEL;
- if (is_full_screen) {
- w = fs_screen_width;
- h = fs_screen_height;
- flags |= SDL_FULLSCREEN;
- } else {
- w = screen_width;
- h = screen_height;
- flags |= SDL_RESIZABLE;
- }
- screen = SDL_SetVideoMode(w, h, 0, flags);
- cur_stream->width = w;
- cur_stream->height = h;
+// SDL_WM_ToggleFullScreen(screen);
}
+ video_open(cur_stream);
}
static void toggle_pause(void)
if (cur_stream) {
screen = SDL_SetVideoMode(event.resize.w, event.resize.h, 0,
SDL_HWSURFACE|SDL_RESIZABLE|SDL_ASYNCBLIT|SDL_HWACCEL);
- cur_stream->width = event.resize.w;
- cur_stream->height = event.resize.h;
+ screen_width = cur_stream->width = event.resize.w;
+ screen_height= cur_stream->height= event.resize.h;
}
break;
case SDL_QUIT:
do_exit();
break;
case FF_ALLOC_EVENT:
+ video_open(event.user.data1);
alloc_picture(event.user.data1);
break;
case FF_REFRESH_EVENT:
}
}
-void opt_width(const char *arg)
+static void opt_frame_size(const char *arg)
+{
+ if (parse_image_size(&frame_width, &frame_height, arg) < 0) {
+ fprintf(stderr, "Incorrect frame size\n");
+ exit(1);
+ }
+ if ((frame_width % 2) != 0 || (frame_height % 2) != 0) {
+ fprintf(stderr, "Frame size must be a multiple of 2\n");
+ exit(1);
+ }
+}
+
+static void opt_width(const char *arg)
{
screen_width = atoi(arg);
+ if(screen_width<=0){
+ fprintf(stderr, "invalid width\n");
+ exit(1);
+ }
}
-void opt_height(const char *arg)
+static void opt_height(const char *arg)
{
screen_height = atoi(arg);
+ if(screen_height<=0){
+ fprintf(stderr, "invalid height\n");
+ exit(1);
+ }
}
static void opt_format(const char *arg)
}
}
+static void opt_frame_pix_fmt(const char *arg)
+{
+ frame_pix_fmt = avcodec_get_pix_fmt(arg);
+}
+
#ifdef CONFIG_NETWORK
-void opt_rtp_tcp(void)
+static void opt_rtp_tcp(void)
{
/* only tcp protocol */
rtsp_default_protocols = (1 << RTSP_PROTOCOL_RTP_TCP);
}
#endif
-void opt_sync(const char *arg)
+static void opt_sync(const char *arg)
{
if (!strcmp(arg, "audio"))
av_sync_type = AV_SYNC_AUDIO_MASTER;
show_help();
}
-void opt_seek(const char *arg)
+static void opt_seek(const char *arg)
{
start_time = parse_date(arg, 1);
}
static void opt_debug(const char *arg)
{
- av_log_set_level(99);
+ av_log_level = 99;
debug = atoi(arg);
}
{ "h", 0, {(void*)show_help}, "show help" },
{ "x", HAS_ARG, {(void*)opt_width}, "force displayed width", "width" },
{ "y", HAS_ARG, {(void*)opt_height}, "force displayed height", "height" },
+ { "s", HAS_ARG | OPT_VIDEO, {(void*)opt_frame_size}, "set frame size (WxH or abbreviation)", "size" },
{ "fs", OPT_BOOL, {(void*)&is_full_screen}, "force full screen" },
{ "an", OPT_BOOL, {(void*)&audio_disable}, "disable audio" },
{ "vn", OPT_BOOL, {(void*)&video_disable}, "disable video" },
+ { "ast", OPT_INT | HAS_ARG | OPT_EXPERT, {(void*)&wanted_audio_stream}, "", "" },
{ "ss", HAS_ARG, {(void*)&opt_seek}, "seek to a given position in seconds", "pos" },
{ "bytes", OPT_BOOL, {(void*)&seek_by_bytes}, "seek by bytes" },
{ "nodisp", OPT_BOOL, {(void*)&display_disable}, "disable graphical display" },
{ "f", HAS_ARG, {(void*)opt_format}, "force format", "fmt" },
+ { "pix_fmt", HAS_ARG | OPT_EXPERT | OPT_VIDEO, {(void*)opt_frame_pix_fmt}, "set pixel format", "format" },
{ "stats", OPT_BOOL | OPT_EXPERT, {(void*)&show_status}, "show status", "" },
{ "debug", HAS_ARG | OPT_EXPERT, {(void*)opt_debug}, "print specific debug info", "" },
{ "bug", OPT_INT | HAS_ARG | OPT_EXPERT, {(void*)&workaround_bugs}, "workaround bugs", "" },
{ "vismv", HAS_ARG | OPT_EXPERT, {(void*)opt_vismv}, "visualize motion vectors", "" },
{ "fast", OPT_BOOL | OPT_EXPERT, {(void*)&fast}, "non spec compliant optimizations", "" },
{ "genpts", OPT_BOOL | OPT_EXPERT, {(void*)&genpts}, "generate pts", "" },
+ { "drp", OPT_BOOL |OPT_EXPERT, {(void*)&decoder_reorder_pts}, "let decoder reorder pts", ""},
{ "lowres", OPT_INT | HAS_ARG | OPT_EXPERT, {(void*)&lowres}, "", "" },
{ "skiploop", OPT_INT | HAS_ARG | OPT_EXPERT, {(void*)&skip_loop_filter}, "", "" },
{ "skipframe", OPT_INT | HAS_ARG | OPT_EXPERT, {(void*)&skip_frame}, "", "" },
/* Called from the main */
int main(int argc, char **argv)
{
- int flags, w, h;
+ int flags;
/* register all codecs, demux and protocols */
av_register_all();
fs_screen_width = vi->current_w;
fs_screen_height = vi->current_h;
#endif
- flags = SDL_HWSURFACE|SDL_ASYNCBLIT|SDL_HWACCEL;
- if (is_full_screen && fs_screen_width) {
- w = fs_screen_width;
- h = fs_screen_height;
- flags |= SDL_FULLSCREEN;
- } else {
- w = screen_width;
- h = screen_height;
- flags |= SDL_RESIZABLE;
- }
-#ifndef CONFIG_DARWIN
- screen = SDL_SetVideoMode(w, h, 0, flags);
-#else
- /* setting bits_per_pixel = 0 or 32 causes blank video on OS X */
- screen = SDL_SetVideoMode(w, h, 24, flags);
-#endif
- if (!screen) {
- fprintf(stderr, "SDL: could not set video mode - exiting\n");
- exit(1);
- }
- SDL_WM_SetCaption("FFplay", "FFplay");
}
SDL_EventState(SDL_ACTIVEEVENT, SDL_IGNORE);
SDL_EventState(SDL_SYSWMEVENT, SDL_IGNORE);
SDL_EventState(SDL_USEREVENT, SDL_IGNORE);
+ av_init_packet(&flush_pkt);
+ flush_pkt.data= "FLUSH";
+
cur_stream = stream_open(input_filename, file_iformat);
event_loop();