int seek_req;
int seek_flags;
int64_t seek_pos;
+ int64_t seek_rel;
AVFormatContext *ic;
int dtg_active_format;
uint8_t *audio_buf;
unsigned int audio_buf_size; /* in bytes */
int audio_buf_index; /* in bytes */
+ AVPacket audio_pkt_temp;
AVPacket audio_pkt;
- uint8_t *audio_pkt_data;
- int audio_pkt_size;
enum SampleFormat audio_src_fmt;
AVAudioConvert *reformat_ctx;
static int video_disable;
static int wanted_audio_stream= 0;
static int wanted_video_stream= 0;
+static int wanted_subtitle_stream= -1;
static int seek_by_bytes;
static int display_disable;
static int show_status;
q->last_pkt->next = pkt1;
q->last_pkt = pkt1;
q->nb_packets++;
- q->size += pkt1->pkt.size;
+ q->size += pkt1->pkt.size + sizeof(*pkt1);
/* XXX: should duplicate packet data in DV case */
SDL_CondSignal(q->cond);
if (!q->first_pkt)
q->last_pkt = NULL;
q->nb_packets--;
- q->size -= pkt1->pkt.size;
+ q->size -= pkt1->pkt.size + sizeof(*pkt1);
*pkt = pkt1->pkt;
av_free(pkt1);
ret = 1;
cb = dst->data[1] + (dsty >> 1) * dst->linesize[1];
cr = dst->data[2] + (dsty >> 1) * dst->linesize[2];
- width2 = (dstw + 1) >> 1;
+ width2 = ((dstw + 1) >> 1) + (dstx & ~dstw & 1);
skip2 = dstx >> 1;
wrap = dst->linesize[0];
wrap3 = rect->pict.linesize[0];
lum[0] = ALPHA_BLEND(a, lum[0], y, 0);
cb[0] = ALPHA_BLEND(a >> 2, cb[0], u, 0);
cr[0] = ALPHA_BLEND(a >> 2, cr[0], v, 0);
+ p++;
+ lum++;
}
- p += wrap3 + (wrap3 - dstw * BPP);
- lum += wrap + (wrap - dstw - dstx);
+ p += wrap3 - dstw * BPP;
+ lum += wrap - dstw - dstx;
cb += dst->linesize[1] - width2 - skip2;
cr += dst->linesize[2] - width2 - skip2;
}
a1 = a;
lum[0] = ALPHA_BLEND(a, lum[0], y, 0);
- YUVA_IN(y, u, v, a, p, pal);
+ YUVA_IN(y, u, v, a, p + BPP, pal);
u1 += u;
v1 += v;
a1 += a;
a1 += a;
lum[0] = ALPHA_BLEND(a, lum[0], y, 0);
- YUVA_IN(y, u, v, a, p, pal);
+ YUVA_IN(y, u, v, a, p + BPP, pal);
u1 += u;
v1 += v;
a1 += a;
}
/* seek in the stream */
-static void stream_seek(VideoState *is, int64_t pos, int rel)
+static void stream_seek(VideoState *is, int64_t pos, int64_t rel)
{
if (!is->seek_req) {
is->seek_pos = pos;
- is->seek_flags = rel < 0 ? AVSEEK_FLAG_BACKWARD : 0;
+ is->seek_rel = rel;
if (seek_by_bytes)
is->seek_flags |= AVSEEK_FLAG_BYTE;
is->seek_req = 1;
}
}
+static double compute_frame_delay(double frame_current_pts, VideoState *is)
+{
+ double actual_delay, delay, sync_threshold, ref_clock, diff;
+
+ /* compute nominal delay */
+ delay = frame_current_pts - is->frame_last_pts;
+ if (delay <= 0 || delay >= 10.0) {
+ /* if incorrect delay, use previous one */
+ delay = is->frame_last_delay;
+ } else {
+ is->frame_last_delay = delay;
+ }
+ is->frame_last_pts = frame_current_pts;
+
+ /* update delay to follow master synchronisation source */
+ if (((is->av_sync_type == AV_SYNC_AUDIO_MASTER && is->audio_st) ||
+ is->av_sync_type == AV_SYNC_EXTERNAL_CLOCK)) {
+ /* if video is slave, we try to correct big delays by
+ duplicating or deleting a frame */
+ ref_clock = get_master_clock(is);
+ diff = frame_current_pts - ref_clock;
+
+ /* skip or repeat frame. We take into account the
+ delay to compute the threshold. I still don't know
+ if it is the best guess */
+ sync_threshold = FFMAX(AV_SYNC_THRESHOLD, delay);
+ if (fabs(diff) < AV_NOSYNC_THRESHOLD) {
+ if (diff <= -sync_threshold)
+ delay = 0;
+ else if (diff >= sync_threshold)
+ delay = 2 * delay;
+ }
+ }
+
+ is->frame_timer += delay;
+ /* compute the REAL delay (we need to do that to avoid
+ long term errors */
+ actual_delay = is->frame_timer - (av_gettime() / 1000000.0);
+ if (actual_delay < 0.010) {
+ /* XXX: should skip picture */
+ actual_delay = 0.010;
+ }
+
+#if defined(DEBUG_SYNC)
+ printf("video: delay=%0.3f actual_delay=%0.3f pts=%0.3f A-V=%f\n",
+ delay, actual_delay, frame_current_pts, -diff);
+#endif
+
+ return actual_delay;
+}
+
/* called to display each frame */
static void video_refresh_timer(void *opaque)
{
VideoState *is = opaque;
VideoPicture *vp;
- double actual_delay, delay, sync_threshold, ref_clock, diff;
SubPicture *sp, *sp2;
is->video_current_pts = vp->pts;
is->video_current_pts_time = av_gettime();
- /* compute nominal delay */
- delay = vp->pts - is->frame_last_pts;
- if (delay <= 0 || delay >= 10.0) {
- /* if incorrect delay, use previous one */
- delay = is->frame_last_delay;
- }
- is->frame_last_delay = delay;
- is->frame_last_pts = vp->pts;
-
- /* update delay to follow master synchronisation source */
- if (((is->av_sync_type == AV_SYNC_AUDIO_MASTER && is->audio_st) ||
- is->av_sync_type == AV_SYNC_EXTERNAL_CLOCK)) {
- /* if video is slave, we try to correct big delays by
- duplicating or deleting a frame */
- ref_clock = get_master_clock(is);
- diff = vp->pts - ref_clock;
-
- /* skip or repeat frame. We take into account the
- delay to compute the threshold. I still don't know
- if it is the best guess */
- sync_threshold = FFMAX(AV_SYNC_THRESHOLD, delay);
- if (fabs(diff) < AV_NOSYNC_THRESHOLD) {
- if (diff <= -sync_threshold)
- delay = 0;
- else if (diff >= sync_threshold)
- delay = 2 * delay;
- }
- }
-
- is->frame_timer += delay;
- /* compute the REAL delay (we need to do that to avoid
- long term errors */
- actual_delay = is->frame_timer - (av_gettime() / 1000000.0);
- if (actual_delay < 0.010) {
- /* XXX: should skip picture */
- actual_delay = 0.010;
- }
/* launch timer for next picture */
- schedule_refresh(is, (int)(actual_delay * 1000 + 0.5));
-
-#if defined(DEBUG_SYNC)
- printf("video: delay=%0.3f actual_delay=%0.3f pts=%0.3f A-V=%f\n",
- delay, actual_delay, vp->pts, -diff);
-#endif
+ schedule_refresh(is, (int)(compute_frame_delay(vp->pts, is) * 1000 + 0.5));
if(is->subtitle_st) {
if (is->subtitle_stream_changed) {
{
VideoPicture *vp;
int dst_pix_fmt;
- AVPicture pict;
static struct SwsContext *img_convert_ctx;
/* wait until we have space to put a new picture */
/* if the frame is not skipped, then display it */
if (vp->bmp) {
+ AVPicture pict;
+
/* get a pointer on the bitmap */
SDL_LockYUVOverlay (vp->bmp);
dst_pix_fmt = PIX_FMT_YUV420P;
+ memset(&pict,0,sizeof(AVPicture));
pict.data[0] = vp->bmp->pixels[0];
pict.data[1] = vp->bmp->pixels[2];
pict.data[2] = vp->bmp->pixels[1];
/* NOTE: ipts is the PTS of the _first_ picture beginning in
this packet, if any */
is->video_st->codec->reordered_opaque= pkt->pts;
- len1 = avcodec_decode_video(is->video_st->codec,
+ len1 = avcodec_decode_video2(is->video_st->codec,
frame, &got_picture,
- pkt->data, pkt->size);
+ pkt);
if( (decoder_reorder_pts || pkt->dts == AV_NOPTS_VALUE)
&& frame->reordered_opaque != AV_NOPTS_VALUE)
if (pkt->pts != AV_NOPTS_VALUE)
pts = av_q2d(is->subtitle_st->time_base)*pkt->pts;
- len1 = avcodec_decode_subtitle(is->subtitle_st->codec,
+ len1 = avcodec_decode_subtitle2(is->subtitle_st->codec,
&sp->sub, &got_subtitle,
- pkt->data, pkt->size);
+ pkt);
// 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, double *pts_ptr)
{
+ AVPacket *pkt_temp = &is->audio_pkt_temp;
AVPacket *pkt = &is->audio_pkt;
AVCodecContext *dec= is->audio_st->codec;
int n, len1, data_size;
for(;;) {
/* NOTE: the audio packet can contain several frames */
- while (is->audio_pkt_size > 0) {
+ while (pkt_temp->size > 0) {
data_size = sizeof(is->audio_buf1);
- len1 = avcodec_decode_audio2(dec,
+ len1 = avcodec_decode_audio3(dec,
(int16_t *)is->audio_buf1, &data_size,
- is->audio_pkt_data, is->audio_pkt_size);
+ pkt_temp);
if (len1 < 0) {
/* if error, we skip the frame */
- is->audio_pkt_size = 0;
+ pkt_temp->size = 0;
break;
}
- is->audio_pkt_data += len1;
- is->audio_pkt_size -= len1;
+ pkt_temp->data += len1;
+ pkt_temp->size -= len1;
if (data_size <= 0)
continue;
continue;
}
- is->audio_pkt_data = pkt->data;
- is->audio_pkt_size = pkt->size;
+ pkt_temp->data = pkt->data;
+ pkt_temp->size = pkt->size;
/* if update the audio clock with the pts */
if (pkt->pts != AV_NOPTS_VALUE) {
enc->error_recognition= error_recognition;
enc->error_concealment= error_concealment;
- set_context_opts(enc, avctx_opts[enc->codec_type], 0);
+ set_context_opts(enc, avcodec_opts[enc->codec_type], 0);
if (!codec ||
avcodec_open(enc, codec) < 0)
static void dump_stream_info(const AVFormatContext *s)
{
- if (s->track != 0)
- fprintf(stderr, "Track: %d\n", s->track);
- if (s->title[0] != '\0')
- fprintf(stderr, "Title: %s\n", s->title);
- if (s->author[0] != '\0')
- fprintf(stderr, "Author: %s\n", s->author);
- if (s->copyright[0] != '\0')
- fprintf(stderr, "Copyright: %s\n", s->copyright);
- if (s->comment[0] != '\0')
- fprintf(stderr, "Comment: %s\n", s->comment);
- if (s->album[0] != '\0')
- fprintf(stderr, "Album: %s\n", s->album);
- if (s->year != 0)
- fprintf(stderr, "Year: %d\n", s->year);
- if (s->genre[0] != '\0')
- fprintf(stderr, "Genre: %s\n", s->genre);
+ AVMetadataTag *tag = NULL;
+ while ((tag=av_metadata_get(s->metadata,"",tag,AV_METADATA_IGNORE_SUFFIX)))
+ fprintf(stderr, "%s: %s\n", tag->key, tag->value);
}
/* since we have only one decoding thread, we can use a global
{
VideoState *is = arg;
AVFormatContext *ic;
- int err, i, ret, video_index, audio_index;
+ int err, i, ret, video_index, audio_index, subtitle_index;
AVPacket pkt1, *pkt = &pkt1;
AVFormatParameters params, *ap = ¶ms;
+ int eof=0;
video_index = -1;
audio_index = -1;
+ subtitle_index = -1;
is->video_stream = -1;
is->audio_stream = -1;
is->subtitle_stream = -1;
/* add the stream start time */
if (ic->start_time != AV_NOPTS_VALUE)
timestamp += ic->start_time;
- ret = av_seek_frame(ic, -1, timestamp, AVSEEK_FLAG_BACKWARD);
+ ret = avformat_seek_file(ic, -1, INT64_MIN, timestamp, INT64_MAX, 0);
if (ret < 0) {
fprintf(stderr, "%s: could not seek to position %0.3f\n",
is->filename, (double)timestamp / AV_TIME_BASE);
ic->streams[i]->discard = AVDISCARD_ALL;
switch(enc->codec_type) {
case CODEC_TYPE_AUDIO:
- if ((audio_index < 0 || wanted_audio_stream-- > 0) && !audio_disable)
+ if (wanted_audio_stream-- >= 0 && !audio_disable)
audio_index = i;
break;
case CODEC_TYPE_VIDEO:
- if ((video_index < 0 || wanted_video_stream-- > 0) && !video_disable)
+ if (wanted_video_stream-- >= 0 && !video_disable)
video_index = i;
break;
+ case CODEC_TYPE_SUBTITLE:
+ if (wanted_subtitle_stream-- >= 0 && !video_disable)
+ subtitle_index = i;
+ break;
default:
break;
}
is->show_audio = 1;
}
+ if (subtitle_index >= 0) {
+ stream_component_open(is, subtitle_index);
+ }
+
if (is->video_stream < 0 && is->audio_stream < 0) {
fprintf(stderr, "%s: could not open codecs\n", is->filename);
ret = -1;
else
av_read_play(ic);
}
-#if defined(CONFIG_RTSP_DEMUXER) || defined(CONFIG_MMSH_PROTOCOL)
- if (is->paused &&
- (!strcmp(ic->iformat->name, "rtsp") ||
- (ic->pb && !strcmp(url_fileno(ic->pb)->prot->name, "mmsh")))) {
+#if CONFIG_RTSP_DEMUXER
+ if (is->paused && !strcmp(ic->iformat->name, "rtsp")) {
/* wait 10 ms to avoid trying to get another packet */
/* XXX: horrible */
SDL_Delay(10);
}
#endif
if (is->seek_req) {
- int stream_index= -1;
int64_t seek_target= is->seek_pos;
+ int64_t seek_min= is->seek_rel > 0 ? seek_target - is->seek_rel + 2: INT64_MIN;
+ int64_t seek_max= is->seek_rel < 0 ? seek_target - is->seek_rel - 2: INT64_MAX;
+//FIXME the +-2 is due to rounding being not done in the correct direction in generation
+// of the seek_pos/seek_rel variables
- 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);
+ ret = avformat_seek_file(is->ic, -1, seek_min, seek_target, seek_max, is->seek_flags);
if (ret < 0) {
fprintf(stderr, "%s: error while seeking\n", is->ic->filename);
}else{
SDL_Delay(10);
continue;
}
- if(url_feof(ic->pb)) {
+ if(url_feof(ic->pb) || eof) {
+ if(is->video_stream >= 0){
av_init_packet(pkt);
pkt->data=NULL;
pkt->size=0;
pkt->stream_index= is->video_stream;
packet_queue_put(&is->videoq, pkt);
+ }
+ SDL_Delay(10);
continue;
}
ret = av_read_frame(ic, pkt);
if (ret < 0) {
- if (url_ferror(ic->pb) == 0) {
- SDL_Delay(100); /* wait for user event */
- continue;
- } else
+ if (ret == AVERROR_EOF)
+ eof=1;
+ if (url_ferror(ic->pb))
break;
+ SDL_Delay(100); /* wait for user event */
+ continue;
}
if (pkt->stream_index == is->audio_stream) {
packet_queue_put(&is->audioq, pkt);
} else {
pos = get_master_clock(cur_stream);
pos += incr;
- stream_seek(cur_stream, (int64_t)(pos * AV_TIME_BASE), incr);
+ stream_seek(cur_stream, (int64_t)(pos * AV_TIME_BASE), (int64_t)(incr * AV_TIME_BASE));
}
}
break;
static int opt_thread_count(const char *opt, const char *arg)
{
thread_count= parse_number_or_die(opt, arg, OPT_INT64, 0, INT_MAX);
-#if !defined(HAVE_THREADS)
+#if !HAVE_THREADS
fprintf(stderr, "Warning: not compiled with thread support, using thread emulation\n");
#endif
return 0;
{ "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}, "", "" },
- { "vst", OPT_INT | HAS_ARG | OPT_EXPERT, {(void*)&wanted_video_stream}, "", "" },
+ { "ast", OPT_INT | HAS_ARG | OPT_EXPERT, {(void*)&wanted_audio_stream}, "select desired audio stream", "stream_number" },
+ { "vst", OPT_INT | HAS_ARG | OPT_EXPERT, {(void*)&wanted_video_stream}, "select desired video stream", "stream_number" },
+ { "sst", OPT_INT | HAS_ARG | OPT_EXPERT, {(void*)&wanted_subtitle_stream}, "select desired subtitle stream", "stream_number" },
{ "ss", HAS_ARG | OPT_FUNC2, {(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" },
av_register_all();
for(i=0; i<CODEC_TYPE_NB; i++){
- avctx_opts[i]= avcodec_alloc_context2(i);
+ avcodec_opts[i]= avcodec_alloc_context2(i);
}
- avformat_opts = av_alloc_format_context();
+ avformat_opts = avformat_alloc_context();
sws_opts = sws_getContext(16,16,0, 16,16,0, sws_flags, NULL,NULL,NULL);
show_banner();
}
if (!display_disable) {
-#ifdef HAVE_SDL_VIDEO_SIZE
+#if HAVE_SDL_VIDEO_SIZE
const SDL_VideoInfo *vi = SDL_GetVideoInfo();
fs_screen_width = vi->current_w;
fs_screen_height = vi->current_h;