📄 ffplay.c
字号:
SDL_LockMutex(is->subpq_mutex); is->subpq_size--; SDL_CondSignal(is->subpq_cond); SDL_UnlockMutex(is->subpq_mutex); } } } } /* display picture */ video_display(is); /* update queue size and signal for next picture */ if (++is->pictq_rindex == VIDEO_PICTURE_QUEUE_SIZE) is->pictq_rindex = 0; SDL_LockMutex(is->pictq_mutex); is->pictq_size--; SDL_CondSignal(is->pictq_cond); SDL_UnlockMutex(is->pictq_mutex); } } else if (is->audio_st) { /* draw the next audio frame */ schedule_refresh(is, 40); /* if only audio stream, then display the audio bars (better than nothing, just to test the implementation */ /* display picture */ video_display(is); } else { schedule_refresh(is, 100); } if (show_status) { static int64_t last_time; int64_t cur_time; int aqsize, vqsize, sqsize; double av_diff; cur_time = av_gettime(); if (!last_time || (cur_time - last_time) >= 500 * 1000) { aqsize = 0; vqsize = 0; sqsize = 0; if (is->audio_st) aqsize = is->audioq.size; if (is->video_st) vqsize = is->videoq.size; if (is->subtitle_st) sqsize = is->subtitleq.size; av_diff = 0; if (is->audio_st && is->video_st) av_diff = get_audio_clock(is) - get_video_clock(is); printf("%7.2f A-V:%7.3f aq=%5dKB vq=%5dKB sq=%5dB \r", get_master_clock(is), av_diff, aqsize / 1024, vqsize / 1024, sqsize); fflush(stdout); last_time = cur_time; } }}/* allocate a picture (needs to do that in main thread to avoid potential locking problems */void alloc_picture(void *opaque){ VideoState *is = opaque; VideoPicture *vp; vp = &is->pictq[is->pictq_windex]; if (vp->bmp) SDL_FreeYUVOverlay(vp->bmp);#if 0 /* XXX: use generic function */ /* XXX: disable overlay if no hardware acceleration or if RGB format */ switch(is->video_st->codec->pix_fmt) { case PIX_FMT_YUV420P: case PIX_FMT_YUV422P: case PIX_FMT_YUV444P: case PIX_FMT_YUV422: case PIX_FMT_YUV410P: case PIX_FMT_YUV411P: is_yuv = 1; break; default: is_yuv = 0; break; }#endif vp->bmp = SDL_CreateYUVOverlay(is->video_st->codec->width, is->video_st->codec->height, SDL_YV12_OVERLAY, screen); vp->width = is->video_st->codec->width; vp->height = is->video_st->codec->height; SDL_LockMutex(is->pictq_mutex); vp->allocated = 1; SDL_CondSignal(is->pictq_cond); 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){ VideoPicture *vp; int dst_pix_fmt; AVPicture pict; static struct SwsContext *img_convert_ctx; /* wait until we have space to put a new picture */ SDL_LockMutex(is->pictq_mutex); while (is->pictq_size >= VIDEO_PICTURE_QUEUE_SIZE && !is->videoq.abort_request) { SDL_CondWait(is->pictq_cond, is->pictq_mutex); } SDL_UnlockMutex(is->pictq_mutex); if (is->videoq.abort_request) return -1; vp = &is->pictq[is->pictq_windex]; /* alloc or resize hardware picture buffer */ if (!vp->bmp || vp->width != is->video_st->codec->width || vp->height != is->video_st->codec->height) { SDL_Event event; vp->allocated = 0; /* the allocation must be done in the main thread to avoid locking problems */ event.type = FF_ALLOC_EVENT; event.user.data1 = is; SDL_PushEvent(&event); /* wait until the picture is allocated */ SDL_LockMutex(is->pictq_mutex); while (!vp->allocated && !is->videoq.abort_request) { SDL_CondWait(is->pictq_cond, is->pictq_mutex); } SDL_UnlockMutex(is->pictq_mutex); if (is->videoq.abort_request) return -1; } /* if the frame is not skipped, then display it */ if (vp->bmp) { /* get a pointer on the bitmap */ SDL_LockYUVOverlay (vp->bmp); dst_pix_fmt = PIX_FMT_YUV420P; 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]; if (img_convert_ctx == NULL) { img_convert_ctx = sws_getContext(is->video_st->codec->width, is->video_st->codec->height, is->video_st->codec->pix_fmt, is->video_st->codec->width, is->video_st->codec->height, dst_pix_fmt, sws_flags, NULL, NULL, NULL); if (img_convert_ctx == NULL) { fprintf(stderr, "Cannot initialize the conversion context\n"); exit(1); } } sws_scale(img_convert_ctx, src_frame->data, src_frame->linesize, 0, is->video_st->codec->height, pict.data, pict.linesize); /* update the bitmap content */ SDL_UnlockYUVOverlay(vp->bmp); vp->pts = pts; /* now we can update the picture count */ if (++is->pictq_windex == VIDEO_PICTURE_QUEUE_SIZE) is->pictq_windex = 0; SDL_LockMutex(is->pictq_mutex); is->pictq_size++; SDL_UnlockMutex(is->pictq_mutex); } 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){ 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;#if defined(DEBUG_SYNC) && 0 { int ftype; if (src_frame->pict_type == FF_B_TYPE) ftype = 'B'; else if (src_frame->pict_type == FF_I_TYPE) ftype = 'I'; else ftype = 'P'; printf("frame_type=%c clock=%0.3f pts=%0.3f\n", ftype, pts, pts1); }#endif return queue_picture(is, src_frame, pts);}static int video_thread(void *arg){ VideoState *is = arg; AVPacket pkt1, *pkt = &pkt1; int len1, got_picture; AVFrame *frame= avcodec_alloc_frame(); double pts; for(;;) { while (is->paused && !is->videoq.abort_request) { SDL_Delay(10); } 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; len1 = avcodec_decode_video(is->video_st->codec, frame, &got_picture, pkt->data, pkt->size);// if (len1 < 0)// break; if (got_picture) { if (output_picture2(is, frame, pts) < 0) goto the_end; } av_free_packet(pkt); if (step) if (cur_stream) stream_pause(cur_stream); } the_end: av_free(frame); return 0;}static int subtitle_thread(void *arg){ VideoState *is = arg; SubPicture *sp; AVPacket pkt1, *pkt = &pkt1; int len1, got_subtitle; double pts; int i, j; int r, g, b, y, u, v, a; for(;;) { while (is->paused && !is->subtitleq.abort_request) { SDL_Delay(10); } 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) { SDL_CondWait(is->subpq_cond, is->subpq_mutex); } SDL_UnlockMutex(is->subpq_mutex); if (is->subtitleq.abort_request) goto the_end; sp = &is->subpq[is->subpq_windex]; /* NOTE: ipts is the PTS of the _first_ picture beginning in this packet, if any */ pts = 0; if (pkt->pts != AV_NOPTS_VALUE) pts = av_q2d(is->subtitle_st->time_base)*pkt->pts; len1 = avcodec_decode_subtitle(is->subtitle_st->codec, &sp->sub, &got_subtitle, pkt->data, pkt->size);// if (len1 < 0)// break; if (got_subtitle && sp->sub.format == 0) { sp->pts = pts; for (i = 0; i < sp->sub.num_rects; i++) { for (j = 0; j < sp->sub.rects[i].nb_colors; j++) { RGBA_IN(r, g, b, a, sp->sub.rects[i].rgba_palette + j); y = RGB_TO_Y_CCIR(r, g, b); u = RGB_TO_U_CCIR(r, g, b, 0); v = RGB_TO_V_CCIR(r, g, b, 0); YUVA_OUT(sp->sub.rects[i].rgba_palette + j, y, u, v, a); } } /* now we can update the picture count */ if (++is->subpq_windex == SUBPICTURE_QUEUE_SIZE) is->subpq_windex = 0; SDL_LockMutex(is->subpq_mutex); is->subpq_size++; SDL_UnlockMutex(is->subpq_mutex); } av_free_packet(pkt);// if (step)// if (cur_stream)// stream_pause(cur_stream); } the_end: return 0;}/* copy samples for viewing in editor window */static void update_sample_display(VideoState *is, short *samples, int samples_size){ int size, len, channels; channels = is->audio_st->codec->channels; size = samples_size / sizeof(short); while (size > 0) { len = SAMPLE_ARRAY_SIZE - is->sample_array_index; if (len > size) len = size; memcpy(is->sample_array + is->sample_array_index, samples, len * sizeof(short)); samples += len; is->sample_array_index += len; if (is->sample_array_index >= SAMPLE_ARRAY_SIZE) is->sample_array_index = 0; size -= len; }}/* return the new audio buffer size (samples can be added or deleted to get better sync if video or external master clock) */static int synchronize_audio(VideoState *is, short *samples, int samples_size1, double pts){ int n, samples_size; double ref_clock; n = 2 * is->audio_st->codec->channels; samples_size = samples_size1; /* if not master, then we try to remove or add samples to correct the clock */ if (((is->av_sync_type == AV_SYNC_VIDEO_MASTER && is->video_st) || is->av_sync_type == AV_SYNC_EXTERNAL_CLOCK)) { double diff, avg_diff; int wanted_size, min_size, max_size, nb_samples; ref_clock = get_master_clock(is); diff = get_audio_clock(is) - ref_clock; if (diff < AV_NOSYNC_THRESHOLD) { is->audio_diff_cum = diff + is->audio_diff_avg_coef * is->audio_diff_cum; if (is->audio_diff_avg_count < AUDIO_DIFF_AVG_NB) { /* not enough measures to have a correct estimate */ is->audio_diff_avg_count++; } else { /* estimate the A-V difference */ avg_diff = is->audio_diff_cum * (1.0 - is->audio_diff_avg_coef); if (fabs(avg_diff) >= is->audio_diff_threshold) { wanted_size = samples_size + ((int)(diff * is->audio_st->codec->sample_rate) * n); nb_samples = samples_size / n; min_size = ((nb_samples * (100 - SAMPLE_CORRECTION_PERCENT_MAX)) / 100) * n; max_size = ((nb_samples * (100 + SAMPLE_CORRECTION_PERCENT_MAX)) / 100) * n; if (wanted_size < min_size) wanted_size = min_size; else if (wanted_size > max_size) wanted_size = max_size; /* add or remove samples to correction the synchro */ if (wanted_size < samples_size) { /* remove samples */ samples_size = wanted_size; } else if (wanted_size > samples_size) { uint8_t *samples_end, *q; int nb; /* add samples */ nb = (samples_size - wanted_size); samples_end = (uint8_t *)samples + samples_size - n; q = samples_end + n; while (nb > 0) { memcpy(q, samples_end, n); q += n; nb -= n; } samples_size = wanted_size; } }#if 0 printf("diff=%f adiff=%f sample_diff=%d apts=%0.3f vpts=%0.3f %f\n", diff, avg_diff, samples_size - samples_size1, is->audio_clock, is->video_clock, is->audio_diff_threshold);#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -