/*
- * ffplay : Simple Media Player based on the Libav libraries
+ * ffplay : Simple Media Player based on the FFmpeg libraries
* Copyright (c) 2003 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "libavutil/dict.h"
#include "libavutil/parseutils.h"
#include "libavutil/samplefmt.h"
+#include "libavutil/avassert.h"
#include "libavformat/avformat.h"
#include "libavdevice/avdevice.h"
#include "libswscale/swscale.h"
#include "libavcodec/avfft.h"
#if CONFIG_AVFILTER
+# include "libavfilter/avcodec.h"
# include "libavfilter/avfilter.h"
# include "libavfilter/avfiltergraph.h"
+# include "libavfilter/buffersink.h"
#endif
-#include "cmdutils.h"
-
#include <SDL.h>
#include <SDL_thread.h>
-#ifdef __MINGW32__
-#undef main /* We don't want SDL to override our main() */
-#endif
+#include "cmdutils.h"
#include <unistd.h>
#include <assert.h>
typedef struct VideoPicture {
double pts; ///<presentation time stamp for this picture
double target_clock; ///<av_gettime() time at which this should be displayed ideally
+ double duration; ///<expected duration of the frame
int64_t pos; ///<byte position in file
SDL_Overlay *bmp;
int width, height; /* source height & width */
};
typedef struct VideoState {
- SDL_Thread *parse_tid;
+ SDL_Thread *read_tid;
SDL_Thread *video_tid;
SDL_Thread *refresh_tid;
AVInputFormat *iformat;
int64_t seek_rel;
int read_pause_return;
AVFormatContext *ic;
- int dtg_active_format;
int audio_stream;
uint8_t *audio_buf;
unsigned int audio_buf_size; /* in bytes */
int audio_buf_index; /* in bytes */
+ int audio_write_buf_size;
AVPacket audio_pkt_temp;
AVPacket audio_pkt;
enum AVSampleFormat audio_src_fmt;
AVAudioConvert *reformat_ctx;
+ double audio_current_pts;
+ double audio_current_pts_drift;
- int show_audio; /* if true, display audio samples */
+ enum ShowMode {
+ SHOW_MODE_NONE = -1, SHOW_MODE_VIDEO = 0, SHOW_MODE_WAVES, SHOW_MODE_RDFT, SHOW_MODE_NB
+ } show_mode;
int16_t sample_array[SAMPLE_ARRAY_SIZE];
int sample_array_index;
int last_i_start;
struct SwsContext *img_convert_ctx;
#endif
- // QETimer *video_timer;
char filename[1024];
int width, height, xleft, ytop;
-
- PtsCorrectionContext pts_ctx;
+ int step;
#if CONFIG_AVFILTER
AVFilterContext *out_video_filter; ///<the last filter in the video chain
int refresh;
} VideoState;
-static void show_help(void);
+static int opt_help(const char *opt, const char *arg);
/* options specified by the user */
static AVInputFormat *file_iformat;
static int fs_screen_height;
static int screen_width = 0;
static int screen_height = 0;
-static enum PixelFormat frame_pix_fmt = PIX_FMT_NONE;
static int audio_disable;
static int video_disable;
static int wanted_stream[AVMEDIA_TYPE_NB]={
static int av_sync_type = AV_SYNC_AUDIO_MASTER;
static int64_t start_time = AV_NOPTS_VALUE;
static int64_t duration = AV_NOPTS_VALUE;
-static int debug = 0;
-static int debug_mv = 0;
-static int step = 0;
static int thread_count = 1;
static int workaround_bugs = 1;
static int fast = 0;
static int exit_on_keydown;
static int exit_on_mousedown;
static int loop=1;
-static int framedrop=1;
+static int framedrop=-1;
+static enum ShowMode show_mode = SHOW_MODE_NONE;
static int rdftspeed=20;
#if CONFIG_AVFILTER
/* current context */
static int is_full_screen;
-static VideoState *cur_stream;
static int64_t audio_callback_time;
static AVPacket flush_pkt;
static SDL_Surface *screen;
-static int packet_queue_put(PacketQueue *q, AVPacket *pkt);
-
-/* packet queue handling */
-static void packet_queue_init(PacketQueue *q)
-{
- memset(q, 0, sizeof(PacketQueue));
- q->mutex = SDL_CreateMutex();
- q->cond = SDL_CreateCond();
- packet_queue_put(q, &flush_pkt);
-}
-
-static void packet_queue_flush(PacketQueue *q)
-{
- AVPacketList *pkt, *pkt1;
-
- SDL_LockMutex(q->mutex);
- for(pkt = q->first_pkt; pkt != NULL; pkt = pkt1) {
- pkt1 = pkt->next;
- av_free_packet(&pkt->pkt);
- av_freep(&pkt);
- }
- q->last_pkt = NULL;
- q->first_pkt = NULL;
- q->nb_packets = 0;
- q->size = 0;
- SDL_UnlockMutex(q->mutex);
-}
-
-static void packet_queue_end(PacketQueue *q)
+void exit_program(int ret)
{
- packet_queue_flush(q);
- SDL_DestroyMutex(q->mutex);
- SDL_DestroyCond(q->cond);
+ exit(ret);
}
static int packet_queue_put(PacketQueue *q, AVPacket *pkt)
return 0;
}
+/* packet queue handling */
+static void packet_queue_init(PacketQueue *q)
+{
+ memset(q, 0, sizeof(PacketQueue));
+ q->mutex = SDL_CreateMutex();
+ q->cond = SDL_CreateCond();
+ packet_queue_put(q, &flush_pkt);
+}
+
+static void packet_queue_flush(PacketQueue *q)
+{
+ AVPacketList *pkt, *pkt1;
+
+ SDL_LockMutex(q->mutex);
+ for(pkt = q->first_pkt; pkt != NULL; pkt = pkt1) {
+ pkt1 = pkt->next;
+ av_free_packet(&pkt->pkt);
+ av_freep(&pkt);
+ }
+ q->last_pkt = NULL;
+ q->first_pkt = NULL;
+ q->nb_packets = 0;
+ q->size = 0;
+ SDL_UnlockMutex(q->mutex);
+}
+
+static void packet_queue_end(PacketQueue *q)
+{
+ packet_queue_flush(q);
+ SDL_DestroyMutex(q->mutex);
+ SDL_DestroyCond(q->cond);
+}
+
static void packet_queue_abort(PacketQueue *q)
{
SDL_LockMutex(q->mutex);
vp = &is->pictq[is->pictq_rindex];
if (vp->bmp) {
#if CONFIG_AVFILTER
- if (vp->picref->video->pixel_aspect.num == 0)
+ if (vp->picref->video->sample_aspect_ratio.num == 0)
aspect_ratio = 0;
else
- aspect_ratio = av_q2d(vp->picref->video->pixel_aspect);
+ aspect_ratio = av_q2d(vp->picref->video->sample_aspect_ratio);
#else
/* XXX: use variable in the frame */
aspect_ratio = 1.0;
aspect_ratio *= (float)vp->width / (float)vp->height;
- if (is->subtitle_st)
- {
- if (is->subpq_size > 0)
- {
+ if (is->subtitle_st) {
+ if (is->subpq_size > 0) {
sp = &is->subpq[is->subpq_rindex];
- if (vp->pts >= sp->pts + ((float) sp->sub.start_display_time / 1000))
- {
+ if (vp->pts >= sp->pts + ((float) sp->sub.start_display_time / 1000)) {
SDL_LockYUVOverlay (vp->bmp);
pict.data[0] = vp->bmp->pixels[0];
is->no_background = 0;
rect.x = is->xleft + x;
rect.y = is->ytop + y;
- rect.w = width;
- rect.h = height;
+ rect.w = FFMAX(width, 1);
+ rect.h = FFMAX(height, 1);
SDL_DisplayYUVOverlay(vp->bmp, &rect);
}
}
-/* get the current audio output buffer size, in samples. With SDL, we
- cannot have a precise information */
-static int audio_write_get_buf_size(VideoState *is)
-{
- return is->audio_buf_size - is->audio_buf_index;
-}
-
static inline int compute_mod(int a, int b)
{
- a = a % b;
- if (a >= 0)
- return a;
- else
- return a + b;
+ return a < 0 ? a%b + b : a%b;
}
static void video_audio_display(VideoState *s)
channels = s->audio_st->codec->channels;
nb_display_channels = channels;
if (!s->paused) {
- int data_used= s->show_audio==1 ? s->width : (2*nb_freq);
+ int data_used= s->show_mode == SHOW_MODE_WAVES ? s->width : (2*nb_freq);
n = 2 * channels;
- delay = audio_write_get_buf_size(s);
+ delay = s->audio_write_buf_size;
delay /= n;
/* to be more precise, we take into account the time spent since
delay = data_used;
i_start= x = compute_mod(s->sample_array_index - delay * channels, SAMPLE_ARRAY_SIZE);
- if(s->show_audio==1){
+ if (s->show_mode == SHOW_MODE_WAVES) {
h= INT_MIN;
for(i=0; i<1000; i+=channels){
int idx= (SAMPLE_ARRAY_SIZE + x - i) % SAMPLE_ARRAY_SIZE;
}
bgcolor = SDL_MapRGB(screen->format, 0x00, 0x00, 0x00);
- if(s->show_audio==1){
+ if (s->show_mode == SHOW_MODE_WAVES) {
fill_rectangle(screen,
s->xleft, s->ytop, s->width, s->height,
bgcolor);
}
}
+static void stream_close(VideoState *is)
+{
+ VideoPicture *vp;
+ int i;
+ /* XXX: use a special url_shutdown call to abort parse cleanly */
+ is->abort_request = 1;
+ SDL_WaitThread(is->read_tid, NULL);
+ SDL_WaitThread(is->refresh_tid, NULL);
+
+ /* free all pictures */
+ for(i=0;i<VIDEO_PICTURE_QUEUE_SIZE; i++) {
+ vp = &is->pictq[i];
+#if CONFIG_AVFILTER
+ if (vp->picref) {
+ avfilter_unref_buffer(vp->picref);
+ vp->picref = NULL;
+ }
+#endif
+ if (vp->bmp) {
+ SDL_FreeYUVOverlay(vp->bmp);
+ vp->bmp = NULL;
+ }
+ }
+ SDL_DestroyMutex(is->pictq_mutex);
+ SDL_DestroyCond(is->pictq_cond);
+ SDL_DestroyMutex(is->subpq_mutex);
+ SDL_DestroyCond(is->subpq_cond);
+#if !CONFIG_AVFILTER
+ if (is->img_convert_ctx)
+ sws_freeContext(is->img_convert_ctx);
+#endif
+ av_free(is);
+}
+
+static void do_exit(VideoState *is)
+{
+ if (is) {
+ stream_close(is);
+ }
+ av_lockmgr_register(NULL);
+ uninit_opts();
+#if CONFIG_AVFILTER
+ avfilter_uninit();
+#endif
+ if (show_status)
+ printf("\n");
+ SDL_Quit();
+ av_log(NULL, AV_LOG_QUIET, "%s", "");
+ exit(0);
+}
+
static int video_open(VideoState *is){
int flags = SDL_HWSURFACE|SDL_ASYNCBLIT|SDL_HWACCEL;
int w,h;
#endif
if (!screen) {
fprintf(stderr, "SDL: could not set video mode - exiting\n");
- return -1;
+ do_exit(is);
}
if (!window_title)
window_title = input_filename;
static void video_display(VideoState *is)
{
if(!screen)
- video_open(cur_stream);
- if (is->audio_st && is->show_audio)
+ video_open(is);
+ if (is->audio_st && is->show_mode != SHOW_MODE_VIDEO)
video_audio_display(is);
else if (is->video_st)
video_image_display(is);
is->refresh=1;
SDL_PushEvent(&event);
}
- usleep(is->audio_st && is->show_audio ? rdftspeed*1000 : 5000); //FIXME ideally we should wait the correct time but SDLs event passing is so slow it would be silly
+ //FIXME ideally we should wait the correct time but SDLs event passing is so slow it would be silly
+ usleep(is->audio_st && is->show_mode != SHOW_MODE_VIDEO ? rdftspeed*1000 : 5000);
}
return 0;
}
/* get the current audio clock value */
static double get_audio_clock(VideoState *is)
{
- double pts;
- int hw_buf_size, bytes_per_sec;
- pts = is->audio_clock;
- hw_buf_size = audio_write_get_buf_size(is);
- bytes_per_sec = 0;
- if (is->audio_st) {
- bytes_per_sec = is->audio_st->codec->sample_rate *
- 2 * is->audio_st->codec->channels;
+ if (is->paused) {
+ return is->audio_current_pts;
+ } else {
+ return is->audio_current_pts_drift + av_gettime() / 1000000.0;
}
- if (bytes_per_sec)
- pts -= (double)hw_buf_size / bytes_per_sec;
- return pts;
}
/* get the current video clock value */
}
/* pause or resume the video */
-static void stream_pause(VideoState *is)
+static void stream_toggle_pause(VideoState *is)
{
if (is->paused) {
is->frame_timer += av_gettime() / 1000000.0 + is->video_current_pts_drift - is->video_current_pts;
}
/* called to display each frame */
-static void video_refresh_timer(void *opaque)
+static void video_refresh(void *opaque)
{
VideoState *is = opaque;
VideoPicture *vp;
assert(nextvp->target_clock >= vp->target_clock);
next_target= nextvp->target_clock;
}else{
- next_target= vp->target_clock + is->video_clock - vp->pts; //FIXME pass durations cleanly
+ next_target= vp->target_clock + vp->duration;
}
- if(framedrop && time > next_target){
+ if((framedrop>0 || (framedrop && is->audio_st)) && time > next_target){
is->skip_frames *= 1.0 + FRAME_SKIP_FACTOR;
if(is->pictq_size > 1 || time > next_target + 0.5){
/* update queue size and signal for next picture */
if (is->audio_st && is->video_st)
av_diff = get_audio_clock(is) - get_video_clock(is);
printf("%7.2f A-V:%7.3f s:%3.1f aq=%5dKB vq=%5dKB sq=%5dB f=%"PRId64"/%"PRId64" \r",
- get_master_clock(is), av_diff, FFMAX(is->skip_frames-1, 0), aqsize / 1024, vqsize / 1024, sqsize, is->pts_ctx.num_faulty_dts, is->pts_ctx.num_faulty_pts);
+ get_master_clock(is),
+ av_diff,
+ FFMAX(is->skip_frames-1, 0),
+ aqsize / 1024,
+ vqsize / 1024,
+ sqsize,
+ is->video_st ? is->video_st->codec->pts_correction_num_faulty_dts : 0,
+ is->video_st ? is->video_st->codec->pts_correction_num_faulty_pts : 0);
fflush(stdout);
last_time = cur_time;
}
}
}
-static void stream_close(VideoState *is)
-{
- VideoPicture *vp;
- int i;
- /* XXX: use a special url_shutdown call to abort parse cleanly */
- is->abort_request = 1;
- SDL_WaitThread(is->parse_tid, NULL);
- SDL_WaitThread(is->refresh_tid, NULL);
-
- /* free all pictures */
- for(i=0;i<VIDEO_PICTURE_QUEUE_SIZE; i++) {
- vp = &is->pictq[i];
-#if CONFIG_AVFILTER
- if (vp->picref) {
- avfilter_unref_buffer(vp->picref);
- vp->picref = NULL;
- }
-#endif
- if (vp->bmp) {
- SDL_FreeYUVOverlay(vp->bmp);
- vp->bmp = NULL;
- }
- }
- SDL_DestroyMutex(is->pictq_mutex);
- SDL_DestroyCond(is->pictq_cond);
- SDL_DestroyMutex(is->subpq_mutex);
- SDL_DestroyCond(is->subpq_cond);
-#if !CONFIG_AVFILTER
- if (is->img_convert_ctx)
- sws_freeContext(is->img_convert_ctx);
-#endif
- av_free(is);
-}
-
-static void do_exit(void)
-{
- if (cur_stream) {
- stream_close(cur_stream);
- cur_stream = NULL;
- }
- uninit_opts();
-#if CONFIG_AVFILTER
- avfilter_uninit();
-#endif
- if (show_status)
- printf("\n");
- SDL_Quit();
- av_log(NULL, AV_LOG_QUIET, "");
- exit(0);
-}
-
/* allocate a picture (needs to do that in main thread to avoid
potential locking problems */
static void alloc_picture(void *opaque)
fprintf(stderr, "Error: the video system does not support an image\n"
"size of %dx%d pixels. Try using -lowres or -vf \"scale=w:h\"\n"
"to reduce the image size.\n", vp->width, vp->height );
- do_exit();
+ do_exit(is);
}
SDL_LockMutex(is->pictq_mutex);
SDL_UnlockMutex(is->pictq_mutex);
}
-/**
- *
- * @param pts the dts of the pkt / pts of the frame and guessed if not known
- */
-static int queue_picture(VideoState *is, AVFrame *src_frame, double pts, int64_t pos)
+static int queue_picture(VideoState *is, AVFrame *src_frame, double pts1, int64_t pos)
{
VideoPicture *vp;
-#if CONFIG_AVFILTER
- AVPicture pict_src;
-#else
- int dst_pix_fmt = PIX_FMT_YUV420P;
+ double frame_delay, pts = pts1;
+
+ /* compute the exact PTS for the picture if it is omitted in the stream
+ * pts1 is the dts of the pkt / pts of the frame */
+ if (pts != 0) {
+ /* update video clock with pts, if present */
+ is->video_clock = pts;
+ } else {
+ pts = is->video_clock;
+ }
+ /* update video clock for next frame */
+ frame_delay = av_q2d(is->video_st->codec->time_base);
+ /* for MPEG2, the frame can be repeated, so we update the
+ clock accordingly */
+ frame_delay += src_frame->repeat_pict * (frame_delay * 0.5);
+ is->video_clock += frame_delay;
+
+#if defined(DEBUG_SYNC) && 0
+ printf("frame_type=%c clock=%0.3f pts=%0.3f\n",
+ av_get_picture_type_char(src_frame->pict_type), pts, pts1);
#endif
+
/* wait until we have space to put a new picture */
SDL_LockMutex(is->pictq_mutex);
vp = &is->pictq[is->pictq_windex];
+ vp->duration = frame_delay;
+
/* alloc or resize hardware picture buffer */
if (!vp->bmp ||
#if CONFIG_AVFILTER
while (!vp->allocated && !is->videoq.abort_request) {
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) {
+ while (!vp->allocated) {
+ SDL_CondWait(is->pictq_cond, is->pictq_mutex);
+ }
+ }
SDL_UnlockMutex(is->pictq_mutex);
if (is->videoq.abort_request)
pict.linesize[2] = vp->bmp->pitches[1];
#if CONFIG_AVFILTER
- pict_src.data[0] = src_frame->data[0];
- pict_src.data[1] = src_frame->data[1];
- pict_src.data[2] = src_frame->data[2];
-
- pict_src.linesize[0] = src_frame->linesize[0];
- pict_src.linesize[1] = src_frame->linesize[1];
- pict_src.linesize[2] = src_frame->linesize[2];
-
//FIXME use direct rendering
- av_picture_copy(&pict, &pict_src,
+ av_picture_copy(&pict, (AVPicture *)src_frame,
vp->pix_fmt, vp->width, vp->height);
#else
sws_flags = av_get_int(sws_opts, "sws_flags", NULL);
is->img_convert_ctx = sws_getCachedContext(is->img_convert_ctx,
vp->width, vp->height, vp->pix_fmt, vp->width, vp->height,
- dst_pix_fmt, sws_flags, NULL, NULL, NULL);
+ PIX_FMT_YUV420P, sws_flags, NULL, NULL, NULL);
if (is->img_convert_ctx == NULL) {
fprintf(stderr, "Cannot initialize the conversion context\n");
exit(1);
return 0;
}
-/**
- * compute the exact PTS for the picture if it is omitted in the stream
- * @param pts1 the dts of the pkt / pts of the frame
- */
-static int output_picture2(VideoState *is, AVFrame *src_frame, double pts1, int64_t pos)
-{
- double frame_delay, pts;
-
- pts = pts1;
-
- if (pts != 0) {
- /* update video clock with pts, if present */
- is->video_clock = pts;
- } else {
- pts = is->video_clock;
- }
- /* update video clock for next frame */
- frame_delay = av_q2d(is->video_st->codec->time_base);
- /* for MPEG2, the frame can be repeated, so we update the
- clock accordingly */
- frame_delay += src_frame->repeat_pict * (frame_delay * 0.5);
- is->video_clock += frame_delay;
-
- return queue_picture(is, src_frame, pts, pos);
-}
-
static int get_video_frame(VideoState *is, AVFrame *frame, int64_t *pts, AVPacket *pkt)
{
int got_picture, i;
is->video_current_pos = -1;
SDL_UnlockMutex(is->pictq_mutex);
- init_pts_correction(&is->pts_ctx);
is->frame_last_pts = AV_NOPTS_VALUE;
is->frame_last_delay = 0;
is->frame_timer = (double)av_gettime() / 1000000.0;
if (got_picture) {
if (decoder_reorder_pts == -1) {
- *pts = guess_correct_pts(&is->pts_ctx, frame->pkt_pts, frame->pkt_dts);
+ *pts = frame->best_effort_timestamp;
} else if (decoder_reorder_pts) {
*pts = frame->pkt_pts;
} else {
unsigned edge;
int pixel_size;
+ av_assert0(codec->flags & CODEC_FLAG_EMU_EDGE);
+
if (codec->codec->capabilities & CODEC_CAP_NEG_LINESIZES)
perms |= AV_PERM_NEG_LINESIZES;
w = codec->width;
h = codec->height;
+
+ if(av_image_check_size(w, h, 0, codec))
+ return -1;
+
avcodec_align_dimensions2(codec, &w, &h, stride);
edge = codec->flags & CODEC_FLAG_EMU_EDGE ? 0 : avcodec_get_edge_width();
w += edge << 1;
priv->is = opaque;
codec = priv->is->video_st->codec;
codec->opaque = ctx;
- if(codec->codec->capabilities & CODEC_CAP_DR1) {
+ if((codec->codec->capabilities & CODEC_CAP_DR1)
+ ) {
+ av_assert0(codec->flags & CODEC_FLAG_EMU_EDGE);
priv->use_dr1 = 1;
codec->get_buffer = input_get_buffer;
codec->release_buffer = input_release_buffer;
if (ret < 0)
return -1;
- if(priv->use_dr1) {
+ if(priv->use_dr1 && priv->frame->opaque) {
picref = avfilter_ref_buffer(priv->frame->opaque, ~0);
} else {
picref = avfilter_get_video_buffer(link, AV_PERM_WRITE, link->w, link->h);
}
av_free_packet(&pkt);
+ avfilter_copy_frame_props(picref, priv->frame);
picref->pts = pts;
- picref->pos = pkt.pos;
- picref->video->pixel_aspect = priv->is->video_st->codec->sample_aspect_ratio;
+
avfilter_start_frame(link, picref);
avfilter_draw_slice(link, 0, link->h, 1);
avfilter_end_frame(link);
priv->is->video_st->codec->pix_fmt, PIX_FMT_NONE
};
- avfilter_set_common_formats(ctx, avfilter_make_format_list(pix_fmts));
+ avfilter_set_common_pixel_formats(ctx, avfilter_make_format_list(pix_fmts));
return 0;
}
static int input_config_props(AVFilterLink *link)
{
FilterPriv *priv = link->src->priv;
- AVCodecContext *c = priv->is->video_st->codec;
+ AVStream *s = priv->is->video_st;
- link->w = c->width;
- link->h = c->height;
- link->time_base = priv->is->video_st->time_base;
+ link->w = s->codec->width;
+ link->h = s->codec->height;
+ link->sample_aspect_ratio = s->sample_aspect_ratio.num ?
+ s->sample_aspect_ratio : s->codec->sample_aspect_ratio;
+ link->time_base = s->time_base;
return 0;
}
{
char sws_flags_str[128];
int ret;
- FFSinkContext ffsink_ctx = { .pix_fmt = PIX_FMT_YUV420P };
+ enum PixelFormat pix_fmts[] = { PIX_FMT_YUV420P, PIX_FMT_NONE };
+ AVBufferSinkParams *buffersink_params = av_buffersink_params_alloc();
AVFilterContext *filt_src = NULL, *filt_out = NULL;
snprintf(sws_flags_str, sizeof(sws_flags_str), "flags=%d", sws_flags);
graph->scale_sws_opts = av_strdup(sws_flags_str);
if ((ret = avfilter_graph_create_filter(&filt_src, &input_filter, "src",
NULL, is, graph)) < 0)
return ret;
- if ((ret = avfilter_graph_create_filter(&filt_out, &ffsink, "out",
- NULL, &ffsink_ctx, graph)) < 0)
+#if FF_API_OLD_VSINK_API
+ ret = avfilter_graph_create_filter(&filt_out, avfilter_get_by_name("buffersink"), "out",
+ NULL, pix_fmts, graph);
+#else
+ buffersink_params->pixel_fmts = pix_fmts;
+ ret = avfilter_graph_create_filter(&filt_out, avfilter_get_by_name("buffersink"), "out",
+ NULL, buffersink_params, graph);
+#endif
+ av_freep(&buffersink_params);
+ if (ret < 0)
return ret;
if(vfilters) {
- AVFilterInOut *outputs = av_malloc(sizeof(AVFilterInOut));
- AVFilterInOut *inputs = av_malloc(sizeof(AVFilterInOut));
+ AVFilterInOut *outputs = avfilter_inout_alloc();
+ AVFilterInOut *inputs = avfilter_inout_alloc();
outputs->name = av_strdup("in");
outputs->filter_ctx = filt_src;
inputs->pad_idx = 0;
inputs->next = NULL;
- if ((ret = avfilter_graph_parse(graph, vfilters, inputs, outputs, NULL)) < 0)
+ if ((ret = avfilter_graph_parse(graph, vfilters, &inputs, &outputs, NULL)) < 0)
return ret;
- av_freep(&vfilters);
} else {
if ((ret = avfilter_link(filt_src, 0, filt_out, 0)) < 0)
return ret;
{
VideoState *is = arg;
AVFrame *frame= avcodec_alloc_frame();
- int64_t pts_int;
+ int64_t pts_int = AV_NOPTS_VALUE, pos = -1;
double pts;
int ret;
#if CONFIG_AVFILTER
AVFilterGraph *graph = avfilter_graph_alloc();
AVFilterContext *filt_out = NULL;
- int64_t pos;
+ int last_w = is->video_st->codec->width;
+ int last_h = is->video_st->codec->height;
if ((ret = configure_video_filters(graph, is, vfilters)) < 0)
goto the_end;
AVPacket pkt;
#else
AVFilterBufferRef *picref;
- AVRational tb;
+ AVRational tb = filt_out->inputs[0]->time_base;
#endif
while (is->paused && !is->videoq.abort_request)
SDL_Delay(10);
#if CONFIG_AVFILTER
- ret = get_filtered_video_frame(filt_out, frame, &picref, &tb);
+ if ( last_w != is->video_st->codec->width
+ || last_h != is->video_st->codec->height) {
+ av_log(NULL, AV_LOG_INFO, "Frame changed from size:%dx%d to size:%dx%d\n",
+ last_w, last_h, is->video_st->codec->width, is->video_st->codec->height);
+ avfilter_graph_free(&graph);
+ graph = avfilter_graph_alloc();
+ if ((ret = configure_video_filters(graph, is, vfilters)) < 0)
+ goto the_end;
+ filt_out = is->out_video_filter;
+ last_w = is->video_st->codec->width;
+ last_h = is->video_st->codec->height;
+ }
+ ret = av_buffersink_get_buffer_ref(filt_out, &picref, 0);
if (picref) {
+ avfilter_fill_frame_from_video_buffer_ref(frame, picref);
pts_int = picref->pts;
pos = picref->pos;
frame->opaque = picref;
}
#else
ret = get_video_frame(is, frame, &pts_int, &pkt);
+ pos = pkt.pos;
+ av_free_packet(&pkt);
#endif
if (ret < 0) goto the_end;
- if (!ret)
+#if CONFIG_AVFILTER
+ if (!picref)
continue;
+#endif
pts = pts_int*av_q2d(is->video_st->time_base);
-#if CONFIG_AVFILTER
- ret = output_picture2(is, frame, pts, pos);
-#else
- ret = output_picture2(is, frame, pts, pkt.pos);
- av_free_packet(&pkt);
-#endif
+ ret = queue_picture(is, frame, pts, pos);
+
if (ret < 0)
goto the_end;
- if (step)
- if (cur_stream)
- stream_pause(cur_stream);
+ if (is->step)
+ stream_toggle_pause(is);
}
the_end:
#if CONFIG_AVFILTER
{
VideoState *is = opaque;
int audio_size, len1;
+ int bytes_per_sec;
double pts;
audio_callback_time = av_gettime();
is->audio_buf_size = 1024;
memset(is->audio_buf, 0, is->audio_buf_size);
} else {
- if (is->show_audio)
+ if (is->show_mode != SHOW_MODE_VIDEO)
update_sample_display(is, (int16_t *)is->audio_buf, audio_size);
audio_size = synchronize_audio(is, (int16_t *)is->audio_buf, audio_size,
pts);
stream += len1;
is->audio_buf_index += len1;
}
+ bytes_per_sec = is->audio_st->codec->sample_rate *
+ 2 * is->audio_st->codec->channels;
+ is->audio_write_buf_size = is->audio_buf_size - is->audio_buf_index;
+ /* Let's assume the audio driver that is used by SDL has two periods. */
+ is->audio_current_pts = is->audio_clock - (double)(2 * is->audio_hw_buf_size + is->audio_write_buf_size) / bytes_per_sec;
+ is->audio_current_pts_drift = is->audio_current_pts - audio_callback_time / 1000000.0;
}
/* open a given stream. Return 0 if OK */
return -1;
avctx = ic->streams[stream_index]->codec;
- opts = filter_codec_opts(codec_opts, avctx->codec_id, 0);
+ opts = filter_codec_opts(codec_opts, avctx->codec_id, ic, ic->streams[stream_index]);
/* prepare audio output */
if (avctx->codec_type == AVMEDIA_TYPE_AUDIO) {
}
codec = avcodec_find_decoder(avctx->codec_id);
- avctx->debug_mv = debug_mv;
- avctx->debug = debug;
+ if (!codec)
+ return -1;
+
avctx->workaround_bugs = workaround_bugs;
avctx->lowres = lowres;
if(lowres) avctx->flags |= CODEC_FLAG_EMU_EDGE;
avctx->error_concealment= error_concealment;
avctx->thread_count= thread_count;
+ if(codec->capabilities & CODEC_CAP_DR1)
+ avctx->flags |= CODEC_FLAG_EMU_EDGE;
+
if (!codec ||
avcodec_open2(avctx, codec, &opts) < 0)
return -1;
/* prepare audio output */
if (avctx->codec_type == AVMEDIA_TYPE_AUDIO) {
+ if(avctx->sample_rate <= 0 || avctx->channels <= 0){
+ fprintf(stderr, "Invalid sample rate or channel count\n");
+ return -1;
+ }
wanted_spec.freq = avctx->sample_rate;
wanted_spec.format = AUDIO_S16SYS;
wanted_spec.channels = avctx->channels;
}
/* this thread gets the stream from the disk or the network */
-static int decode_thread(void *arg)
+static int read_thread(void *arg)
{
VideoState *is = arg;
AVFormatContext *ic = NULL;
if(genpts)
ic->flags |= AVFMT_FLAG_GENPTS;
- opts = setup_find_stream_info_opts(ic);
+ opts = setup_find_stream_info_opts(ic, codec_opts);
orig_nb_streams = ic->nb_streams;
err = avformat_find_stream_info(ic, opts);
av_dump_format(ic, 0, is->filename, 0);
}
+ is->show_mode = show_mode;
+
/* open the streams */
if (st_index[AVMEDIA_TYPE_AUDIO] >= 0) {
stream_component_open(is, st_index[AVMEDIA_TYPE_AUDIO]);
ret= stream_component_open(is, st_index[AVMEDIA_TYPE_VIDEO]);
}
is->refresh_tid = SDL_CreateThread(refresh_thread, is);
- if(ret<0) {
- if (!display_disable)
- is->show_audio = 2;
- }
+ if (is->show_mode == SHOW_MODE_NONE)
+ is->show_mode = ret >= 0 ? SHOW_MODE_VIDEO : SHOW_MODE_RDFT;
if (st_index[AVMEDIA_TYPE_SUBTITLE] >= 0) {
stream_component_open(is, st_index[AVMEDIA_TYPE_SUBTITLE]);
SDL_Delay(10);
if(is->audioq.size + is->videoq.size + is->subtitleq.size ==0){
if(loop!=1 && (!loop || --loop)){
- stream_seek(cur_stream, start_time != AV_NOPTS_VALUE ? start_time : 0, 0, 0);
+ stream_seek(is, start_time != AV_NOPTS_VALUE ? start_time : 0, 0, 0);
}else if(autoexit){
ret=AVERROR_EOF;
goto fail;
}
}
+ eof=0;
continue;
}
ret = av_read_frame(ic, pkt);
if (ret < 0) {
- if (ret == AVERROR_EOF || (ic->pb && ic->pb->eof_reached))
+ if (ret == AVERROR_EOF || url_feof(ic->pb))
eof=1;
if (ic->pb && ic->pb->error)
break;
is->subpq_cond = SDL_CreateCond();
is->av_sync_type = av_sync_type;
- is->parse_tid = SDL_CreateThread(decode_thread, is);
- if (!is->parse_tid) {
+ is->read_tid = SDL_CreateThread(read_thread, is);
+ if (!is->read_tid) {
av_free(is);
return NULL;
}
}
-static void toggle_full_screen(void)
+static void toggle_full_screen(VideoState *is)
{
is_full_screen = !is_full_screen;
- video_open(cur_stream);
+ video_open(is);
}
-static void toggle_pause(void)
+static void toggle_pause(VideoState *is)
{
- if (cur_stream)
- stream_pause(cur_stream);
- step = 0;
+ stream_toggle_pause(is);
+ is->step = 0;
}
-static void step_to_next_frame(void)
+static void step_to_next_frame(VideoState *is)
{
- if (cur_stream) {
- /* if the stream is paused unpause it, then step */
- if (cur_stream->paused)
- stream_pause(cur_stream);
- }
- step = 1;
+ /* if the stream is paused unpause it, then step */
+ if (is->paused)
+ stream_toggle_pause(is);
+ is->step = 1;
}
-static void toggle_audio_display(void)
+static void toggle_audio_display(VideoState *is)
{
- if (cur_stream) {
- int bgcolor = SDL_MapRGB(screen->format, 0x00, 0x00, 0x00);
- cur_stream->show_audio = (cur_stream->show_audio + 1) % 3;
- fill_rectangle(screen,
- cur_stream->xleft, cur_stream->ytop, cur_stream->width, cur_stream->height,
- bgcolor);
- SDL_UpdateRect(screen, cur_stream->xleft, cur_stream->ytop, cur_stream->width, cur_stream->height);
- }
+ int bgcolor = SDL_MapRGB(screen->format, 0x00, 0x00, 0x00);
+ is->show_mode = (is->show_mode + 1) % SHOW_MODE_NB;
+ fill_rectangle(screen,
+ is->xleft, is->ytop, is->width, is->height,
+ bgcolor);
+ SDL_UpdateRect(screen, is->xleft, is->ytop, is->width, is->height);
}
/* handle an event sent by the GUI */
-static void event_loop(void)
+static void event_loop(VideoState *cur_stream)
{
SDL_Event event;
double incr, pos, frac;
switch(event.type) {
case SDL_KEYDOWN:
if (exit_on_keydown) {
- do_exit();
+ do_exit(cur_stream);
break;
}
switch(event.key.keysym.sym) {
case SDLK_ESCAPE:
case SDLK_q:
- do_exit();
+ do_exit(cur_stream);
break;
case SDLK_f:
- toggle_full_screen();
+ toggle_full_screen(cur_stream);
break;
case SDLK_p:
case SDLK_SPACE:
- toggle_pause();
+ toggle_pause(cur_stream);
break;
case SDLK_s: //S: Step to next frame
- step_to_next_frame();
+ step_to_next_frame(cur_stream);
break;
case SDLK_a:
- if (cur_stream)
- stream_cycle_channel(cur_stream, AVMEDIA_TYPE_AUDIO);
+ stream_cycle_channel(cur_stream, AVMEDIA_TYPE_AUDIO);
break;
case SDLK_v:
- if (cur_stream)
- stream_cycle_channel(cur_stream, AVMEDIA_TYPE_VIDEO);
+ stream_cycle_channel(cur_stream, AVMEDIA_TYPE_VIDEO);
break;
case SDLK_t:
- if (cur_stream)
- stream_cycle_channel(cur_stream, AVMEDIA_TYPE_SUBTITLE);
+ stream_cycle_channel(cur_stream, AVMEDIA_TYPE_SUBTITLE);
break;
case SDLK_w:
- toggle_audio_display();
+ toggle_audio_display(cur_stream);
break;
case SDLK_LEFT:
incr = -10.0;
case SDLK_DOWN:
incr = -60.0;
do_seek:
- if (cur_stream) {
- if (seek_by_bytes) {
- if (cur_stream->video_stream >= 0 && cur_stream->video_current_pos>=0){
- pos= cur_stream->video_current_pos;
- }else if(cur_stream->audio_stream >= 0 && cur_stream->audio_pkt.pos>=0){
- pos= cur_stream->audio_pkt.pos;
- }else
- pos = avio_tell(cur_stream->ic->pb);
- if (cur_stream->ic->bit_rate)
- incr *= cur_stream->ic->bit_rate / 8.0;
- else
- incr *= 180000.0;
- pos += incr;
- stream_seek(cur_stream, pos, incr, 1);
- } else {
- pos = get_master_clock(cur_stream);
- pos += incr;
- stream_seek(cur_stream, (int64_t)(pos * AV_TIME_BASE), (int64_t)(incr * AV_TIME_BASE), 0);
- }
+ if (seek_by_bytes) {
+ if (cur_stream->video_stream >= 0 && cur_stream->video_current_pos>=0){
+ pos= cur_stream->video_current_pos;
+ }else if(cur_stream->audio_stream >= 0 && cur_stream->audio_pkt.pos>=0){
+ pos= cur_stream->audio_pkt.pos;
+ }else
+ pos = avio_tell(cur_stream->ic->pb);
+ if (cur_stream->ic->bit_rate)
+ incr *= cur_stream->ic->bit_rate / 8.0;
+ else
+ incr *= 180000.0;
+ pos += incr;
+ stream_seek(cur_stream, pos, incr, 1);
+ } else {
+ pos = get_master_clock(cur_stream);
+ pos += incr;
+ stream_seek(cur_stream, (int64_t)(pos * AV_TIME_BASE), (int64_t)(incr * AV_TIME_BASE), 0);
}
break;
default:
break;
case SDL_MOUSEBUTTONDOWN:
if (exit_on_mousedown) {
- do_exit();
+ do_exit(cur_stream);
break;
}
case SDL_MOUSEMOTION:
break;
x= event.motion.x;
}
- if (cur_stream) {
- if(seek_by_bytes || cur_stream->ic->duration<=0){
- uint64_t size= avio_size(cur_stream->ic->pb);
- stream_seek(cur_stream, size*x/cur_stream->width, 0, 1);
- }else{
- int64_t ts;
- int ns, hh, mm, ss;
- int tns, thh, tmm, tss;
- tns = cur_stream->ic->duration/1000000LL;
- thh = tns/3600;
- tmm = (tns%3600)/60;
- tss = (tns%60);
- frac = x/cur_stream->width;
- ns = frac*tns;
- hh = ns/3600;
- mm = (ns%3600)/60;
- ss = (ns%60);
- fprintf(stderr, "Seek to %2.0f%% (%2d:%02d:%02d) of total duration (%2d:%02d:%02d) \n", frac*100,
- hh, mm, ss, thh, tmm, tss);
- ts = frac*cur_stream->ic->duration;
- if (cur_stream->ic->start_time != AV_NOPTS_VALUE)
- ts += cur_stream->ic->start_time;
- stream_seek(cur_stream, ts, 0, 0);
- }
+ if(seek_by_bytes || cur_stream->ic->duration<=0){
+ uint64_t size= avio_size(cur_stream->ic->pb);
+ stream_seek(cur_stream, size*x/cur_stream->width, 0, 1);
+ }else{
+ int64_t ts;
+ int ns, hh, mm, ss;
+ int tns, thh, tmm, tss;
+ tns = cur_stream->ic->duration/1000000LL;
+ thh = tns/3600;
+ tmm = (tns%3600)/60;
+ tss = (tns%60);
+ frac = x/cur_stream->width;
+ ns = frac*tns;
+ hh = ns/3600;
+ mm = (ns%3600)/60;
+ ss = (ns%60);
+ fprintf(stderr, "Seek to %2.0f%% (%2d:%02d:%02d) of total duration (%2d:%02d:%02d) \n", frac*100,
+ hh, mm, ss, thh, tmm, tss);
+ ts = frac*cur_stream->ic->duration;
+ if (cur_stream->ic->start_time != AV_NOPTS_VALUE)
+ ts += cur_stream->ic->start_time;
+ stream_seek(cur_stream, ts, 0, 0);
}
break;
case SDL_VIDEORESIZE:
- if (cur_stream) {
- screen = SDL_SetVideoMode(event.resize.w, event.resize.h, 0,
- SDL_HWSURFACE|SDL_RESIZABLE|SDL_ASYNCBLIT|SDL_HWACCEL);
- screen_width = cur_stream->width = event.resize.w;
- screen_height= cur_stream->height= event.resize.h;
- }
+ screen = SDL_SetVideoMode(event.resize.w, event.resize.h, 0,
+ SDL_HWSURFACE|SDL_RESIZABLE|SDL_ASYNCBLIT|SDL_HWACCEL);
+ screen_width = cur_stream->width = event.resize.w;
+ screen_height= cur_stream->height= event.resize.h;
break;
case SDL_QUIT:
case FF_QUIT_EVENT:
- do_exit();
+ do_exit(cur_stream);
break;
case FF_ALLOC_EVENT:
video_open(event.user.data1);
alloc_picture(event.user.data1);
break;
case FF_REFRESH_EVENT:
- video_refresh_timer(event.user.data1);
+ video_refresh(event.user.data1);
cur_stream->refresh=0;
break;
default:
static int opt_frame_size(const char *opt, const char *arg)
{
- av_log(NULL, AV_LOG_ERROR,
- "Option '%s' has been removed, use private format options instead\n", opt);
- return AVERROR(EINVAL);
+ av_log(NULL, AV_LOG_WARNING, "Option -s is deprecated, use -video_size.\n");
+ return opt_default("video_size", arg);
}
static int opt_width(const char *opt, const char *arg)
static int opt_frame_pix_fmt(const char *opt, const char *arg)
{
- frame_pix_fmt = av_get_pix_fmt(arg);
- return 0;
+ av_log(NULL, AV_LOG_WARNING, "Option -pix_fmt is deprecated, use -pixel_format.\n");
+ return opt_default("pixel_format", arg);
}
static int opt_sync(const char *opt, const char *arg)
return 0;
}
-static int opt_debug(const char *opt, const char *arg)
+static int opt_thread_count(const char *opt, const char *arg)
{
- av_log_set_level(99);
- debug = parse_number_or_die(opt, arg, OPT_INT64, 0, INT_MAX);
+ thread_count= parse_number_or_die(opt, arg, OPT_INT64, 0, INT_MAX);
+#if !HAVE_THREADS
+ fprintf(stderr, "Warning: not compiled with thread support, using thread emulation\n");
+#endif
return 0;
}
-static int opt_vismv(const char *opt, const char *arg)
+static int opt_show_mode(const char *opt, const char *arg)
{
- debug_mv = parse_number_or_die(opt, arg, OPT_INT64, INT_MIN, INT_MAX);
+ show_mode = !strcmp(arg, "video") ? SHOW_MODE_VIDEO :
+ !strcmp(arg, "waves") ? SHOW_MODE_WAVES :
+ !strcmp(arg, "rdft" ) ? SHOW_MODE_RDFT :
+ parse_number_or_die(opt, arg, OPT_INT, 0, SHOW_MODE_NB-1);
return 0;
}
-static int opt_thread_count(const char *opt, const char *arg)
+static void opt_input_file(void *optctx, const char *filename)
{
- thread_count= parse_number_or_die(opt, arg, OPT_INT64, 0, INT_MAX);
-#if !HAVE_THREADS
- fprintf(stderr, "Warning: not compiled with thread support, using thread emulation\n");
-#endif
- return 0;
+ if (input_filename) {
+ fprintf(stderr, "Argument '%s' provided as input filename, but '%s' was already specified.\n",
+ filename, input_filename);
+ exit_program(1);
+ }
+ if (!strcmp(filename, "-"))
+ filename = "pipe:";
+ input_filename = filename;
}
+static int dummy;
+
static const OptionDef options[] = {
#include "cmdutils_common_opts.h"
{ "x", HAS_ARG, {(void*)opt_width}, "force displayed width", "width" },
{ "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_INT | HAS_ARG | OPT_EXPERT, {(void*)&decoder_reorder_pts}, "let decoder reorder pts 0=off 1=on -1=auto", ""},
{ "vf", OPT_STRING | HAS_ARG, {(void*)&vfilters}, "video filters", "filter list" },
#endif
{ "rdftspeed", OPT_INT | HAS_ARG| OPT_AUDIO | OPT_EXPERT, {(void*)&rdftspeed}, "rdft speed", "msecs" },
+ { "showmode", HAS_ARG, {(void*)opt_show_mode}, "select show mode (0 = video, 1 = waves, 2 = RDFT)", "mode" },
{ "default", HAS_ARG | OPT_AUDIO | OPT_VIDEO | OPT_EXPERT, {(void*)opt_default}, "generic catch all option", "" },
- { "i", 0, {NULL}, "ffmpeg compatibility dummy option", ""},
+ { "i", OPT_BOOL, {(void *)&dummy}, "read specified file", "input_file"},
{ NULL, },
};
static void show_usage(void)
{
printf("Simple media player\n");
- printf("usage: ffplay [options] input_file\n");
+ printf("usage: %s [options] input_file\n", program_name);
printf("\n");
}
-static void show_help(void)
+static int opt_help(const char *opt, const char *arg)
{
+ const AVClass *class;
av_log_set_callback(log_callback_help);
show_usage();
show_help_options(options, "Main options:\n",
show_help_options(options, "\nAdvanced options:\n",
OPT_EXPERT, OPT_EXPERT);
printf("\n");
- av_opt_show2(avcodec_opts[0], NULL,
+ class = avcodec_get_class();
+ av_opt_show2(&class, NULL,
AV_OPT_FLAG_DECODING_PARAM, 0);
printf("\n");
- av_opt_show2(avformat_opts, NULL,
+ class = avformat_get_class();
+ av_opt_show2(&class, NULL,
AV_OPT_FLAG_DECODING_PARAM, 0);
#if !CONFIG_AVFILTER
printf("\n");
- av_opt_show2(sws_opts, NULL,
+ class = sws_get_class();
+ av_opt_show2(&class, NULL,
AV_OPT_FLAG_ENCODING_PARAM, 0);
#endif
printf("\nWhile playing:\n"
"down/up seek backward/forward 1 minute\n"
"mouse click seek to percentage in file corresponding to fraction of width\n"
);
+ return 0;
}
-static void opt_input_file(const char *filename)
+static int lockmgr(void **mtx, enum AVLockOp op)
{
- if (input_filename) {
- fprintf(stderr, "Argument '%s' provided as input filename, but '%s' was already specified.\n",
- filename, input_filename);
- exit(1);
- }
- if (!strcmp(filename, "-"))
- filename = "pipe:";
- input_filename = filename;
+ switch(op) {
+ case AV_LOCK_CREATE:
+ *mtx = SDL_CreateMutex();
+ if(!*mtx)
+ return 1;
+ return 0;
+ case AV_LOCK_OBTAIN:
+ return !!SDL_LockMutex(*mtx);
+ case AV_LOCK_RELEASE:
+ return !!SDL_UnlockMutex(*mtx);
+ case AV_LOCK_DESTROY:
+ SDL_DestroyMutex(*mtx);
+ return 0;
+ }
+ return 1;
}
/* Called from the main */
int main(int argc, char **argv)
{
int flags;
+ VideoState *is;
av_log_set_flags(AV_LOG_SKIP_REPEATED);
show_banner();
- parse_options(argc, argv, options, opt_input_file);
+ parse_options(NULL, argc, argv, options, opt_input_file);
if (!input_filename) {
show_usage();
fprintf(stderr, "An input file must be specified\n");
- fprintf(stderr, "Use -h to get full help or, even better, run 'man ffplay'\n");
+ fprintf(stderr, "Use -h to get full help or, even better, run 'man %s'\n", program_name);
exit(1);
}
video_disable = 1;
}
flags = SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER;
+ if (audio_disable)
+ flags &= ~SDL_INIT_AUDIO;
#if !defined(__MINGW32__) && !defined(__APPLE__)
flags |= SDL_INIT_EVENTTHREAD; /* Not supported on Windows or Mac OS X */
#endif
if (SDL_Init (flags)) {
fprintf(stderr, "Could not initialize SDL - %s\n", SDL_GetError());
+ fprintf(stderr, "(Did you set the DISPLAY variable?)\n");
exit(1);
}
SDL_EventState(SDL_SYSWMEVENT, SDL_IGNORE);
SDL_EventState(SDL_USEREVENT, SDL_IGNORE);
+ if (av_lockmgr_register(lockmgr)) {
+ fprintf(stderr, "Could not initialize lock manager!\n");
+ do_exit(NULL);
+ }
+
av_init_packet(&flush_pkt);
flush_pkt.data= "FLUSH";
- cur_stream = stream_open(input_filename, file_iformat);
+ is = stream_open(input_filename, file_iformat);
+ if (!is) {
+ fprintf(stderr, "Failed to initialize VideoState!\n");
+ do_exit(NULL);
+ }
- event_loop();
+ event_loop(is);
/* never returns */