X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=ffplay.c;h=18422e282232302ea48f48c9321fc89becb8bd53;hb=33afad545100315e86ca22a27067373379df3aa4;hp=88e6b1a14333a49e1f46dd01a37585856f75f1ba;hpb=b250f9c66d3ddd84652d158fb979a5f21e3f2c71;p=ffmpeg diff --git a/ffplay.c b/ffplay.c index 88e6b1a1433..18422e28223 100644 --- a/ffplay.c +++ b/ffplay.c @@ -110,6 +110,7 @@ typedef struct VideoState { int seek_req; int seek_flags; int64_t seek_pos; + int64_t seek_rel; AVFormatContext *ic; int dtg_active_format; @@ -191,6 +192,7 @@ static int audio_disable; 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; @@ -281,7 +283,7 @@ static int packet_queue_put(PacketQueue *q, AVPacket *pkt) 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); @@ -320,7 +322,7 @@ static int packet_queue_get(PacketQueue *q, AVPacket *pkt, int block) 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; @@ -449,7 +451,7 @@ static void blend_subrect(AVPicture *dst, const AVSubtitleRect *rect, int imgw, 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]; @@ -495,9 +497,11 @@ static void blend_subrect(AVPicture *dst, const AVSubtitleRect *rect, int imgw, 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; } @@ -533,7 +537,7 @@ static void blend_subrect(AVPicture *dst, const AVSubtitleRect *rect, int imgw, 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; @@ -547,7 +551,7 @@ static void blend_subrect(AVPicture *dst, const AVSubtitleRect *rect, int imgw, 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; @@ -981,11 +985,11 @@ static double get_master_clock(VideoState *is) } /* 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; @@ -1002,12 +1006,62 @@ static void stream_pause(VideoState *is) } } +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; @@ -1023,50 +1077,8 @@ static void video_refresh_timer(void *opaque) 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) { @@ -1215,7 +1227,6 @@ static int queue_picture(VideoState *is, AVFrame *src_frame, double pts) { VideoPicture *vp; int dst_pix_fmt; - AVPicture pict; static struct SwsContext *img_convert_ctx; /* wait until we have space to put a new picture */ @@ -1258,10 +1269,13 @@ static int queue_picture(VideoState *is, AVFrame *src_frame, double pts) /* 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]; @@ -1741,7 +1755,7 @@ static int stream_component_open(VideoState *is, int stream_index) 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) @@ -1883,22 +1897,9 @@ static void stream_component_close(VideoState *is, int stream_index) 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 @@ -1915,12 +1916,13 @@ static int decode_thread(void *arg) { 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; video_index = -1; audio_index = -1; + subtitle_index = -1; is->video_stream = -1; is->audio_stream = -1; is->subtitle_stream = -1; @@ -1963,7 +1965,7 @@ static int decode_thread(void *arg) /* 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); @@ -1975,13 +1977,17 @@ static int decode_thread(void *arg) 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; } @@ -2003,6 +2009,10 @@ static int decode_thread(void *arg) 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; @@ -2019,10 +2029,8 @@ static int decode_thread(void *arg) else av_read_play(ic); } -#if CONFIG_RTSP_DEMUXER || 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); @@ -2030,18 +2038,13 @@ static int decode_thread(void *arg) } #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{ @@ -2079,7 +2082,7 @@ static int decode_thread(void *arg) } ret = av_read_frame(ic, pkt); if (ret < 0) { - if (url_ferror(ic->pb) == 0) { + if (ret != AVERROR_EOF && url_ferror(ic->pb) == 0) { SDL_Delay(100); /* wait for user event */ continue; } else @@ -2341,7 +2344,7 @@ static void event_loop(void) } 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; @@ -2484,8 +2487,9 @@ static const OptionDef options[] = { { "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" }, @@ -2552,9 +2556,9 @@ int main(int argc, char **argv) av_register_all(); for(i=0; i