📄 ffmpeg.c
字号:
AVFrame *final_picture, *formatted_picture, *resampling_dst, *padding_src; AVFrame picture_crop_temp, picture_pad_temp; AVCodecContext *enc, *dec; avcodec_get_frame_defaults(&picture_crop_temp); avcodec_get_frame_defaults(&picture_pad_temp); enc = ost->st->codec; dec = ist->st->codec; /* by default, we output a single frame */ nb_frames = 1; *frame_size = 0; if(video_sync_method){ double vdelta; vdelta = get_sync_ipts(ost) / av_q2d(enc->time_base) - ost->sync_opts; //FIXME set to 0.5 after we fix some dts/pts bugs like in avidec.c if (vdelta < -1.1) nb_frames = 0; else if (vdelta > 1.1) nb_frames = lrintf(vdelta);//fprintf(stderr, "vdelta:%f, ost->sync_opts:%"PRId64", ost->sync_ipts:%f nb_frames:%d\n", vdelta, ost->sync_opts, ost->sync_ipts, nb_frames); if (nb_frames == 0){ ++nb_frames_drop; if (verbose>2) fprintf(stderr, "*** drop!\n"); }else if (nb_frames > 1) { nb_frames_dup += nb_frames; if (verbose>2) fprintf(stderr, "*** %d dup!\n", nb_frames-1); } }else ost->sync_opts= lrintf(get_sync_ipts(ost) / av_q2d(enc->time_base)); nb_frames= FFMIN(nb_frames, max_frames[CODEC_TYPE_VIDEO] - ost->frame_number); if (nb_frames <= 0) return; if (ost->video_crop) { if (av_picture_crop((AVPicture *)&picture_crop_temp, (AVPicture *)in_picture, dec->pix_fmt, ost->topBand, ost->leftBand) < 0) { av_log(NULL, AV_LOG_ERROR, "error cropping picture\n"); return; } formatted_picture = &picture_crop_temp; } else { formatted_picture = in_picture; } final_picture = formatted_picture; padding_src = formatted_picture; resampling_dst = &ost->pict_tmp; if (ost->video_pad) { final_picture = &ost->pict_tmp; if (ost->video_resample) { if (av_picture_crop((AVPicture *)&picture_pad_temp, (AVPicture *)final_picture, enc->pix_fmt, ost->padtop, ost->padleft) < 0) { av_log(NULL, AV_LOG_ERROR, "error padding picture\n"); return; } resampling_dst = &picture_pad_temp; } } if (ost->video_resample) { padding_src = NULL; final_picture = &ost->pict_tmp; sws_scale(ost->img_resample_ctx, formatted_picture->data, formatted_picture->linesize, 0, ost->resample_height, resampling_dst->data, resampling_dst->linesize); } if (ost->video_pad) { av_picture_pad((AVPicture*)final_picture, (AVPicture *)padding_src, enc->height, enc->width, enc->pix_fmt, ost->padtop, ost->padbottom, ost->padleft, ost->padright, padcolor); } /* duplicates frame if needed */ for(i=0;i<nb_frames;i++) { AVPacket pkt; av_init_packet(&pkt); pkt.stream_index= ost->index; if (s->oformat->flags & AVFMT_RAWPICTURE) { /* raw pictures are written as AVPicture structure to avoid any copies. We support temorarily the older method. */ AVFrame* old_frame = enc->coded_frame; enc->coded_frame = dec->coded_frame; //FIXME/XXX remove this hack pkt.data= (uint8_t *)final_picture; pkt.size= sizeof(AVPicture); pkt.pts= av_rescale_q(ost->sync_opts, enc->time_base, ost->st->time_base); pkt.flags |= PKT_FLAG_KEY; write_frame(s, &pkt, ost->st->codec, bitstream_filters[ost->file_index][pkt.stream_index]); enc->coded_frame = old_frame; } else { AVFrame big_picture; big_picture= *final_picture; /* better than nothing: use input picture interlaced settings */ big_picture.interlaced_frame = in_picture->interlaced_frame; if(avctx_opts[CODEC_TYPE_VIDEO]->flags & (CODEC_FLAG_INTERLACED_DCT|CODEC_FLAG_INTERLACED_ME)){ if(top_field_first == -1) big_picture.top_field_first = in_picture->top_field_first; else big_picture.top_field_first = top_field_first; } /* handles sameq here. This is not correct because it may not be a global option */ if (same_quality) { big_picture.quality = ist->st->quality; }else big_picture.quality = ost->st->quality; if(!me_threshold) big_picture.pict_type = 0;// big_picture.pts = AV_NOPTS_VALUE; big_picture.pts= ost->sync_opts;// big_picture.pts= av_rescale(ost->sync_opts, AV_TIME_BASE*(int64_t)enc->time_base.num, enc->time_base.den);//av_log(NULL, AV_LOG_DEBUG, "%"PRId64" -> encoder\n", ost->sync_opts); ret = avcodec_encode_video(enc, bit_buffer, bit_buffer_size, &big_picture); if (ret == -1) { fprintf(stderr, "Video encoding failed\n"); exit(1); } //enc->frame_number = enc->real_pict_num; if(ret>0){ pkt.data= bit_buffer; pkt.size= ret; if(enc->coded_frame && enc->coded_frame->pts != AV_NOPTS_VALUE) pkt.pts= av_rescale_q(enc->coded_frame->pts, enc->time_base, ost->st->time_base);/*av_log(NULL, AV_LOG_DEBUG, "encoder -> %"PRId64"/%"PRId64"\n", pkt.pts != AV_NOPTS_VALUE ? av_rescale(pkt.pts, enc->time_base.den, AV_TIME_BASE*(int64_t)enc->time_base.num) : -1, pkt.dts != AV_NOPTS_VALUE ? av_rescale(pkt.dts, enc->time_base.den, AV_TIME_BASE*(int64_t)enc->time_base.num) : -1);*/ if(enc->coded_frame && enc->coded_frame->key_frame) pkt.flags |= PKT_FLAG_KEY; write_frame(s, &pkt, ost->st->codec, bitstream_filters[ost->file_index][pkt.stream_index]); *frame_size = ret; //fprintf(stderr,"\nFrame: %3d %3d size: %5d type: %d", // enc->frame_number-1, enc->real_pict_num, ret, // enc->pict_type); /* if two pass, output log */ if (ost->logfile && enc->stats_out) { fprintf(ost->logfile, "%s", enc->stats_out); } } } ost->sync_opts++; ost->frame_number++; }}static double psnr(double d){ if(d==0) return INFINITY; return -10.0*log(d)/log(10.0);}static void do_video_stats(AVFormatContext *os, AVOutputStream *ost, int frame_size){ AVCodecContext *enc; int frame_number; double ti1, bitrate, avg_bitrate; /* this is executed just the first time do_video_stats is called */ if (!vstats_file) { vstats_file = fopen(vstats_filename, "w"); if (!vstats_file) { perror("fopen"); exit(1); } } enc = ost->st->codec; if (enc->codec_type == CODEC_TYPE_VIDEO) { frame_number = ost->frame_number; fprintf(vstats_file, "frame= %5d q= %2.1f ", frame_number, enc->coded_frame->quality/(float)FF_QP2LAMBDA); if (enc->flags&CODEC_FLAG_PSNR) fprintf(vstats_file, "PSNR= %6.2f ", psnr(enc->coded_frame->error[0]/(enc->width*enc->height*255.0*255.0))); fprintf(vstats_file,"f_size= %6d ", frame_size); /* compute pts value */ ti1 = ost->sync_opts * av_q2d(enc->time_base); if (ti1 < 0.01) ti1 = 0.01; bitrate = (frame_size * 8) / av_q2d(enc->time_base) / 1000.0; avg_bitrate = (double)(video_size * 8) / ti1 / 1000.0; fprintf(vstats_file, "s_size= %8.0fkB time= %0.3f br= %7.1fkbits/s avg_br= %7.1fkbits/s ", (double)video_size / 1024, ti1, bitrate, avg_bitrate); fprintf(vstats_file,"type= %c\n", av_get_pict_type_char(enc->coded_frame->pict_type)); }}static void print_report(AVFormatContext **output_files, AVOutputStream **ost_table, int nb_ostreams, int is_last_report){ char buf[1024]; AVOutputStream *ost; AVFormatContext *oc, *os; int64_t total_size; AVCodecContext *enc; int frame_number, vid, i; double bitrate, ti1, pts; static int64_t last_time = -1; static int qp_histogram[52]; if (!is_last_report) { int64_t cur_time; /* display the report every 0.5 seconds */ cur_time = av_gettime(); if (last_time == -1) { last_time = cur_time; return; } if ((cur_time - last_time) < 500000) return; last_time = cur_time; } oc = output_files[0]; total_size = url_fsize(oc->pb); if(total_size<0) // FIXME improve url_fsize() so it works with non seekable output too total_size= url_ftell(oc->pb); buf[0] = '\0'; ti1 = 1e10; vid = 0; for(i=0;i<nb_ostreams;i++) { ost = ost_table[i]; os = output_files[ost->file_index]; enc = ost->st->codec; if (vid && enc->codec_type == CODEC_TYPE_VIDEO) { snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "q=%2.1f ", enc->coded_frame && !ost->st->stream_copy ? enc->coded_frame->quality/(float)FF_QP2LAMBDA : -1); } if (!vid && enc->codec_type == CODEC_TYPE_VIDEO) { float t = (av_gettime()-timer_start) / 1000000.0; frame_number = ost->frame_number; snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "frame=%5d fps=%3d q=%3.1f ", frame_number, (t>1)?(int)(frame_number/t+0.5) : 0, enc->coded_frame && !ost->st->stream_copy ? enc->coded_frame->quality/(float)FF_QP2LAMBDA : -1); if(is_last_report) snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "L"); if(qp_hist && enc->coded_frame){ int j; int qp= lrintf(enc->coded_frame->quality/(float)FF_QP2LAMBDA); if(qp>=0 && qp<sizeof(qp_histogram)/sizeof(int)) qp_histogram[qp]++; for(j=0; j<32; j++) snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "%X", (int)lrintf(log(qp_histogram[j]+1)/log(2))); } if (enc->flags&CODEC_FLAG_PSNR){ int j; double error, error_sum=0; double scale, scale_sum=0; char type[3]= {'Y','U','V'}; snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "PSNR="); for(j=0; j<3; j++){ if(is_last_report){ error= enc->error[j]; scale= enc->width*enc->height*255.0*255.0*frame_number; }else{ error= enc->coded_frame->error[j]; scale= enc->width*enc->height*255.0*255.0; } if(j) scale/=4; error_sum += error; scale_sum += scale; snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "%c:%2.2f ", type[j], psnr(error/scale)); } snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "*:%2.2f ", psnr(error_sum/scale_sum)); } vid = 1; } /* compute min output value */ pts = (double)ost->st->pts.val * av_q2d(ost->st->time_base); if ((pts < ti1) && (pts > 0)) ti1 = pts; } if (ti1 < 0.01) ti1 = 0.01; if (verbose || is_last_report) { bitrate = (double)(total_size * 8) / ti1 / 1000.0; snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "size=%8.0fkB time=%0.1f bitrate=%6.1fkbits/s", (double)total_size / 1024, ti1, bitrate); if (verbose > 1) snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), " dup=%d drop=%d", nb_frames_dup, nb_frames_drop); if (verbose >= 0) fprintf(stderr, "%s \r", buf); fflush(stderr); } if (is_last_report && verbose >= 0){ int64_t raw= audio_size + video_size + extra_size; fprintf(stderr, "\n"); fprintf(stderr, "video:%1.0fkB audio:%1.0fkB global headers:%1.0fkB muxing overhead %f%%\n", video_size/1024.0, audio_size/1024.0, extra_size/1024.0, 100.0*(total_size - raw)/raw ); }}/* pkt = NULL means EOF (needed to flush decoder buffers) */static int output_packet(AVInputStream *ist, int ist_index, AVOutputStream **ost_table, int nb_ostreams, const AVPacket *pkt){ AVFormatContext *os; AVOutputStream *ost; uint8_t *ptr; int len, ret, i; uint8_t *data_buf; int data_size, got_picture; AVFrame picture; void *buffer_to_free; static unsigned int samples_size= 0; static short *samples= NULL; AVSubtitle subtitle, *subtitle_to_free; int got_subtitle; if(!pkt){ ist->pts= ist->next_pts; // needed for last packet if vsync=0 } else if (pkt->dts != AV_NOPTS_VALUE) { //FIXME seems redundant, as libavformat does this too ist->next_pts = ist->pts = av_rescale_q(pkt->dts, ist->st->time_base, AV_TIME_BASE_Q); } else {// assert(ist->pts == ist->next_pts); } if (pkt == NULL) { /* EOF handling */ ptr = NULL; len = 0; goto handle_eof; } len = pkt->size;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -