📄 ffplay.c
字号:
u1 = u; v1 = v; a1 = a; lum[0] = ALPHA_BLEND(a, lum[0], y, 0); YUVA_IN(y, u, v, a, p + BPP, pal); u1 += u; v1 += v; a1 += a; lum[1] = ALPHA_BLEND(a, lum[1], y, 0); cb[0] = ALPHA_BLEND(a1 >> 2, cb[0], u, 1); cr[0] = ALPHA_BLEND(a1 >> 2, cr[0], v, 1); cb++; cr++; p += 2 * BPP; lum += 2; } if (w) { YUVA_IN(y, u, v, a, p, pal); 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); } }}static void free_subpicture(SubPicture *sp){ int i; for (i = 0; i < sp->sub.num_rects; i++) { av_free(sp->sub.rects[i].bitmap); av_free(sp->sub.rects[i].rgba_palette); } av_free(sp->sub.rects); memset(&sp->sub, 0, sizeof(AVSubtitle));}static void video_image_display(VideoState *is){ VideoPicture *vp; SubPicture *sp; AVPicture pict; float aspect_ratio; int width, height, x, y; SDL_Rect rect; int i; vp = &is->pictq[is->pictq_rindex]; if (vp->bmp) { /* XXX: use variable in the frame */ if (is->video_st->codec->sample_aspect_ratio.num == 0) aspect_ratio = 0; else aspect_ratio = av_q2d(is->video_st->codec->sample_aspect_ratio) * is->video_st->codec->width / is->video_st->codec->height;; if (aspect_ratio <= 0.0) aspect_ratio = (float)is->video_st->codec->width / (float)is->video_st->codec->height; /* if an active format is indicated, then it overrides the mpeg format */#if 0 if (is->video_st->codec->dtg_active_format != is->dtg_active_format) { is->dtg_active_format = is->video_st->codec->dtg_active_format; printf("dtg_active_format=%d\n", is->dtg_active_format); }#endif#if 0 switch(is->video_st->codec->dtg_active_format) { case FF_DTG_AFD_SAME: default: /* nothing to do */ break; case FF_DTG_AFD_4_3: aspect_ratio = 4.0 / 3.0; break; case FF_DTG_AFD_16_9: aspect_ratio = 16.0 / 9.0; break; case FF_DTG_AFD_14_9: aspect_ratio = 14.0 / 9.0; break; case FF_DTG_AFD_4_3_SP_14_9: aspect_ratio = 14.0 / 9.0; break; case FF_DTG_AFD_16_9_SP_14_9: aspect_ratio = 14.0 / 9.0; break; case FF_DTG_AFD_SP_4_3: aspect_ratio = 4.0 / 3.0; break; }#endif 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)) { SDL_LockYUVOverlay (vp->bmp); pict.data[0] = vp->bmp->pixels[0]; pict.data[1] = vp->bmp->pixels[2]; pict.data[2] = vp->bmp->pixels[1]; pict.linesize[0] = vp->bmp->pitches[0]; pict.linesize[1] = vp->bmp->pitches[2]; pict.linesize[2] = vp->bmp->pitches[1]; for (i = 0; i < sp->sub.num_rects; i++) blend_subrect(&pict, &sp->sub.rects[i]); SDL_UnlockYUVOverlay (vp->bmp); } } } /* XXX: we suppose the screen has a 1.0 pixel ratio */ height = is->height; width = ((int)rint(height * aspect_ratio)) & -3; if (width > is->width) { width = is->width; height = ((int)rint(width / aspect_ratio)) & -3; } x = (is->width - width) / 2; y = (is->height - height) / 2; if (!is->no_background) { /* fill the background */ // fill_border(is, x, y, width, height, QERGB(0x00, 0x00, 0x00)); } else { is->no_background = 0; } rect.x = is->xleft + x; rect.y = is->xleft + y; rect.w = width; rect.h = height; SDL_DisplayYUVOverlay(vp->bmp, &rect); } else {#if 0 fill_rectangle(screen, is->xleft, is->ytop, is->width, is->height, QERGB(0x00, 0x00, 0x00));#endif }}static inline int compute_mod(int a, int b){ a = a % b; if (a >= 0) return a; else return a + 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; int16_t time_diff; /* compute display index : center on currently output samples */ channels = s->audio_st->codec->channels; nb_display_channels = channels; if (!s->paused) { n = 2 * channels; delay = audio_write_get_buf_size(s); delay /= n; /* to be more precise, we take into account the time spent since the last buffer computation */ if (audio_callback_time) { time_diff = av_gettime() - audio_callback_time; delay += (time_diff * s->audio_st->codec->sample_rate) / 1000000; } delay -= s->width / 2; if (delay < s->width) delay = s->width; i_start = compute_mod(s->sample_array_index - delay * channels, SAMPLE_ARRAY_SIZE); s->last_i_start = i_start; } else { i_start = s->last_i_start; } bgcolor = SDL_MapRGB(screen->format, 0x00, 0x00, 0x00); fill_rectangle(screen, s->xleft, s->ytop, s->width, s->height, bgcolor); fgcolor = SDL_MapRGB(screen->format, 0xff, 0xff, 0xff); /* total height for one channel */ h = s->height / nb_display_channels; /* graph height / 2 */ h2 = (h * 9) / 20; for(ch = 0;ch < nb_display_channels; ch++) { i = i_start + ch; y1 = s->ytop + ch * h + (h / 2); /* position of center line */ for(x = 0; x < s->width; x++) { y = (s->sample_array[i] * h2) >> 15; if (y < 0) { y = -y; ys = y1 - y; } else { ys = y1; } fill_rectangle(screen, s->xleft + x, ys, 1, y, fgcolor); i += channels; if (i >= SAMPLE_ARRAY_SIZE) i -= SAMPLE_ARRAY_SIZE; } } fgcolor = SDL_MapRGB(screen->format, 0x00, 0x00, 0xff); for(ch = 1;ch < nb_display_channels; ch++) { y = s->ytop + ch * h; fill_rectangle(screen, s->xleft, y, s->width, 1, fgcolor); } SDL_UpdateRect(screen, s->xleft, s->ytop, s->width, s->height);}/* display the current picture, if any */static void video_display(VideoState *is){ if (is->audio_st && is->show_audio) video_audio_display(is); else if (is->video_st) video_image_display(is);}static Uint32 sdl_refresh_timer_cb(Uint32 interval, void *opaque){ SDL_Event event; event.type = FF_REFRESH_EVENT; event.user.data1 = opaque; SDL_PushEvent(&event); return 0; /* 0 means stop timer */}/* schedule a video refresh in 'delay' ms */static void schedule_refresh(VideoState *is, int delay){ SDL_AddTimer(delay, sdl_refresh_timer_cb, is);}/* 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 (bytes_per_sec) pts -= (double)hw_buf_size / bytes_per_sec; return pts;}/* get the current video clock value */static double get_video_clock(VideoState *is){ double delta; if (is->paused) { delta = 0; } else { delta = (av_gettime() - is->video_current_pts_time) / 1000000.0; } return is->video_current_pts + delta;}/* get the current external clock value */static double get_external_clock(VideoState *is){ int64_t ti; ti = av_gettime(); return is->external_clock + ((ti - is->external_clock_time) * 1e-6);}/* get the current master clock value */static double get_master_clock(VideoState *is){ double val; if (is->av_sync_type == AV_SYNC_VIDEO_MASTER) { if (is->video_st) val = get_video_clock(is); else val = get_audio_clock(is); } else if (is->av_sync_type == AV_SYNC_AUDIO_MASTER) { if (is->audio_st) val = get_audio_clock(is); else val = get_video_clock(is); } else { val = get_external_clock(is); } return val;}/* seek in the stream */static void stream_seek(VideoState *is, int64_t pos, int rel){ if (!is->seek_req) { is->seek_pos = pos; is->seek_flags = rel < 0 ? AVSEEK_FLAG_BACKWARD : 0; if (seek_by_bytes) is->seek_flags |= AVSEEK_FLAG_BYTE; is->seek_req = 1; }}/* pause or resume the video */static void stream_pause(VideoState *is){ is->paused = !is->paused; if (is->paused) { is->video_current_pts = get_video_clock(is); }}/* called to display each frame */void video_refresh_timer(void *opaque){ VideoState *is = opaque; VideoPicture *vp; double actual_delay, delay, sync_threshold, ref_clock, diff; SubPicture *sp, *sp2; if (is->video_st) { if (is->pictq_size == 0) { /* if no picture, need to wait */ schedule_refresh(is, 1); } else { /* dequeue the picture */ vp = &is->pictq[is->pictq_rindex]; /* update current video pts */ 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 >= 1.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 = AV_SYNC_THRESHOLD; if (delay > sync_threshold) 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 if(is->subtitle_st) { if (is->subtitle_stream_changed) { SDL_LockMutex(is->subpq_mutex); while (is->subpq_size) { free_subpicture(&is->subpq[is->subpq_rindex]); /* update queue size and signal for next picture */ if (++is->subpq_rindex == SUBPICTURE_QUEUE_SIZE) is->subpq_rindex = 0; is->subpq_size--; } is->subtitle_stream_changed = 0; SDL_CondSignal(is->subpq_cond); SDL_UnlockMutex(is->subpq_mutex); } else { if (is->subpq_size > 0) { sp = &is->subpq[is->subpq_rindex]; if (is->subpq_size > 1) sp2 = &is->subpq[(is->subpq_rindex + 1) % SUBPICTURE_QUEUE_SIZE]; else sp2 = NULL; if ((is->video_current_pts > (sp->pts + ((float) sp->sub.end_display_time / 1000))) || (sp2 && is->video_current_pts > (sp2->pts + ((float) sp2->sub.start_display_time / 1000)))) { free_subpicture(sp); /* update queue size and signal for next picture */ if (++is->subpq_rindex == SUBPICTURE_QUEUE_SIZE) is->subpq_rindex = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -