FFmpeg的FFplay框架分析( 二 )


FFmpeg的FFplay框架分析

文章插图
 
解码:
FFmpeg的FFplay框架分析

文章插图
 
解码完后的数据,插入frame队列 。注意,视频和音频,都各自有自己frame队列 。
FFmpeg的FFplay框架分析

文章插图
 

FFmpeg的FFplay框架分析

文章插图
 
涉及到线程安全,就要加锁 。
FFmpeg的FFplay框架分析

文章插图
【FFmpeg的FFplay框架分析】 
音频基本上也是走的这个流程 。就不再叙述了 。
最后就是显示模块了,取出数据,然后根据当前能支持的播放格式和尺寸,看看是否要格式转换,也就是是否要调用sws_scale 。
static void video_image_display(VideoState *is){Frame *vp;Frame *sp = NULL;SDL_Rect rect;//从frame队列取数据vp = frame_queue_peek_last(&is->pictq);if (is->subtitle_st) {if (frame_queue_nb_remaining(&is->subpq) > 0) {sp = frame_queue_peek(&is->subpq);if (vp->pts >= sp->pts + ((float) sp->sub.start_display_time / 1000)) {if (!sp->uploaded) {uint8_t* pixels[4];int pitch[4];int i;if (!sp->width || !sp->height) {sp->width = vp->width;sp->height = vp->height;}if (realloc_texture(&is->sub_texture, SDL_PIXELFORMAT_ARGB8888, sp->width, sp->height, SDL_BLENDMODE_BLEND, 1) < 0)return;for (i = 0; i < sp->sub.num_rects; i++) {AVSubtitleRect *sub_rect = sp->sub.rects[i];sub_rect->x = av_clip(sub_rect->x, 0, sp->width );sub_rect->y = av_clip(sub_rect->y, 0, sp->height);sub_rect->w = av_clip(sub_rect->w, 0, sp->width- sub_rect->x);sub_rect->h = av_clip(sub_rect->h, 0, sp->height - sub_rect->y);is->sub_convert_ctx = sws_getCachedContext(is->sub_convert_ctx,sub_rect->w, sub_rect->h, AV_PIX_FMT_PAL8,sub_rect->w, sub_rect->h, AV_PIX_FMT_BGRA,0, NULL, NULL, NULL);if (!is->sub_convert_ctx) {av_log(NULL, AV_LOG_FATAL, "Cannot initialize the conversion contextn");return;}if (!SDL_LockTexture(is->sub_texture, (SDL_Rect *)sub_rect, (void **)pixels, pitch)) {//格式转换sws_scale(is->sub_convert_ctx, (const uint8_t * const *)sub_rect->data, sub_rect->linesize,0, sub_rect->h, pixels, pitch);SDL_UnlockTexture(is->sub_texture);}}sp->uploaded = 1;}} elsesp = NULL;}}//计算显示区域calculate_display_rect(&rect, is->xleft, is->ytop, is->width, is->height, vp->width, vp->height, vp->sar);if (!vp->uploaded) {if (upload_texture(&is->vid_texture, vp->frame, &is->img_convert_ctx) < 0)return;vp->uploaded = 1;vp->flip_v = vp->frame->linesize[0] < 0;}set_sdl_yuv_conversion_mode(vp->frame);SDL_RenderCopyEx(renderer, is->vid_texture, NULL, &rect, 0, NULL, vp->flip_v ? SDL_FLIP_VERTICAL : 0);set_sdl_yuv_conversion_mode(NULL);if (sp) {#if USE_ONEPASS_SUBTITLE_RENDERSDL_RenderCopy(renderer, is->sub_texture, NULL, &rect);#elseint i;double xratio = (double)rect.w / (double)sp->width;double yratio = (double)rect.h / (double)sp->height;for (i = 0; i < sp->sub.num_rects; i++) {SDL_Rect *sub_rect = (SDL_Rect*)sp->sub.rects[i];SDL_Rect target = {.x = rect.x + sub_rect->x * xratio,.y = rect.y + sub_rect->y * yratio,.w = sub_rect->w * xratio,.h = sub_rect->h * yratio};SDL_RenderCopy(renderer, is->sub_texture, sub_rect, &target);}#endif}}static int audio_decode_frame(VideoState *is){int data_size, resampled_data_size;int64_t dec_channel_layout;av_unused double audio_clock0;int wanted_nb_samples;Frame *af;if (is->paused)return -1;do {#if defined(_WIN32)while (frame_queue_nb_remaining(&is->sampq) == 0) {if ((av_gettime_relative() - audio_callback_time) > 1000000LL * is->audio_hw_buf_size / is->audio_tgt.bytes_per_sec / 2)return -1;av_usleep (1000);}#endifif (!(af = frame_queue_peek_readable(&is->sampq)))return -1;frame_queue_next(&is->sampq);} while (af->serial != is->audioq.serial);data_size = av_samples_get_buffer_size(NULL, af->frame->channels,af->frame->nb_samples,af->frame->format, 1);dec_channel_layout =(af->frame->channel_layout && af->frame->channels == av_get_channel_layout_nb_channels(af->frame->channel_layout)) ?af->frame->channel_layout : av_get_default_channel_layout(af->frame->channels);wanted_nb_samples = synchronize_audio(is, af->frame->nb_samples);if (af->frame->format!= is->audio_src.fmt||dec_channel_layout!= is->audio_src.channel_layout ||af->frame->sample_rate!= is->audio_src.freq||(wanted_nb_samples!= af->frame->nb_samples && !is->swr_ctx)) {swr_free(&is->swr_ctx);is->swr_ctx = swr_alloc_set_opts(NULL,is->audio_tgt.channel_layout, is->audio_tgt.fmt, is->audio_tgt.freq,dec_channel_layout,af->frame->format, af->frame->sample_rate,0, NULL);if (!is->swr_ctx || swr_init(is->swr_ctx) < 0) {av_log(NULL, AV_LOG_ERROR,"Cannot create sample rate converter for conversion of %d Hz %s %d channels to %d Hz %s %d channels!n",af->frame->sample_rate, av_get_sample_fmt_name(af->frame->format), af->frame->channels,is->audio_tgt.freq, av_get_sample_fmt_name(is->audio_tgt.fmt), is->audio_tgt.channels);swr_free(&is->swr_ctx);return -1;}is->audio_src.channel_layout = dec_channel_layout;is->audio_src.channels= af->frame->channels;is->audio_src.freq = af->frame->sample_rate;is->audio_src.fmt = af->frame->format;}if (is->swr_ctx) {const uint8_t **in = (const uint8_t **)af->frame->extended_data;uint8_t **out = &is->audio_buf1;int out_count = (int64_t)wanted_nb_samples * is->audio_tgt.freq / af->frame->sample_rate + 256;int out_size= av_samples_get_buffer_size(NULL, is->audio_tgt.channels, out_count, is->audio_tgt.fmt, 0);int len2;if (out_size < 0) {av_log(NULL, AV_LOG_ERROR, "av_samples_get_buffer_size() failedn");return -1;}if (wanted_nb_samples != af->frame->nb_samples) {if (swr_set_compensation(is->swr_ctx, (wanted_nb_samples - af->frame->nb_samples) * is->audio_tgt.freq / af->frame->sample_rate,wanted_nb_samples * is->audio_tgt.freq / af->frame->sample_rate) < 0) {av_log(NULL, AV_LOG_ERROR, "swr_set_compensation() failedn");return -1;}}av_fast_malloc(&is->audio_buf1, &is->audio_buf1_size, out_size);if (!is->audio_buf1)return AVERROR(ENOMEM);len2 = swr_convert(is->swr_ctx, out, out_count, in, af->frame->nb_samples);if (len2 < 0) {av_log(NULL, AV_LOG_ERROR, "swr_convert() failedn");return -1;}if (len2 == out_count) {av_log(NULL, AV_LOG_WARNING, "audio buffer is probably too smalln");if (swr_init(is->swr_ctx) < 0)swr_free(&is->swr_ctx);}is->audio_buf = is->audio_buf1;resampled_data_size = len2 * is->audio_tgt.channels * av_get_bytes_per_sample(is->audio_tgt.fmt);} else {is->audio_buf = af->frame->data[0];resampled_data_size = data_size;}audio_clock0 = is->audio_clock;/* update the audio clock with the pts */if (!isnan(af->pts))is->audio_clock = af->pts + (double) af->frame->nb_samples / af->frame->sample_rate;elseis->audio_clock = NAN;is->audio_clock_serial = af->serial;#ifdef DEBUG{static double last_clock;printf("audio: delay=%0.3f clock=%0.3f clock0=%0.3fn",is->audio_clock - last_clock,is->audio_clock, audio_clock0);last_clock = is->audio_clock;}#endifreturn resampled_data_size;}


推荐阅读