diff --git a/ffmpeg.c b/ffmpeg.c index 990ce0edff..a3f4bbdc00 100644 --- a/ffmpeg.c +++ b/ffmpeg.c @@ -791,6 +791,197 @@ static void print_report(AVFormatContext **output_files, fprintf(stderr, "\n"); } +/* pkt = NULL means EOF (needed to flush decoder buffers) */ +static int output_packet(AVInputStream *ist, int ist_index, + AVOutputStream **ost_table, int nb_ostreams, + AVPacket *pkt) +{ + AVFormatContext *os; + AVOutputStream *ost; + uint8_t *ptr; + int len, ret, i; + uint8_t *data_buf; + int data_size, got_picture; + AVFrame picture; + short samples[AVCODEC_MAX_AUDIO_FRAME_SIZE / 2]; + void *buffer_to_free; + + if (pkt && pkt->pts != AV_NOPTS_VALUE) { + ist->pts = pkt->pts; + } else { + ist->pts = ist->next_pts; + } + + if (pkt == NULL) { + /* EOF handling */ + ptr = NULL; + len = 0; + goto handle_eof; + } + + len = pkt->size; + ptr = pkt->data; + while (len > 0) { + handle_eof: + /* decode the packet if needed */ + data_buf = NULL; /* fail safe */ + data_size = 0; + if (ist->decoding_needed) { + switch(ist->st->codec.codec_type) { + case CODEC_TYPE_AUDIO: + /* XXX: could avoid copy if PCM 16 bits with same + endianness as CPU */ + ret = avcodec_decode_audio(&ist->st->codec, samples, &data_size, + ptr, len); + if (ret < 0) + goto fail_decode; + ptr += ret; + len -= ret; + /* Some bug in mpeg audio decoder gives */ + /* data_size < 0, it seems they are overflows */ + if (data_size <= 0) { + /* no audio frame */ + continue; + } + data_buf = (uint8_t *)samples; + ist->next_pts += ((int64_t)AV_TIME_BASE * data_size) / + (2 * ist->st->codec.channels); + break; + case CODEC_TYPE_VIDEO: + data_size = (ist->st->codec.width * ist->st->codec.height * 3) / 2; + /* XXX: allocate picture correctly */ + memset(&picture, 0, sizeof(picture)); + ret = avcodec_decode_video(&ist->st->codec, + &picture, &got_picture, ptr, len); + ist->st->quality= picture.quality; + if (ret < 0) + goto fail_decode; + if (!got_picture) { + /* no picture yet */ + goto discard_packet; + } + if (ist->st->codec.frame_rate_base != 0) { + ist->next_pts += ((int64_t)AV_TIME_BASE * + ist->st->codec.frame_rate_base) / + ist->st->codec.frame_rate; + } + len = 0; + break; + default: + goto fail_decode; + } + } else { + data_buf = ptr; + data_size = len; + ret = len; + len = 0; + } + + buffer_to_free = NULL; + if (ist->st->codec.codec_type == CODEC_TYPE_VIDEO) { + pre_process_video_frame(ist, (AVPicture *)&picture, + &buffer_to_free); + } + + /* frame rate emulation */ + if (ist->st->codec.rate_emu) { + int64_t pts = av_rescale((int64_t) ist->frame * ist->st->codec.frame_rate_base, 1000000, ist->st->codec.frame_rate); + int64_t now = av_gettime() - ist->start; + if (pts > now) + usleep(pts - now); + + ist->frame++; + } + +#if 0 + /* mpeg PTS deordering : if it is a P or I frame, the PTS + is the one of the next displayed one */ + /* XXX: add mpeg4 too ? */ + if (ist->st->codec.codec_id == CODEC_ID_MPEG1VIDEO) { + if (ist->st->codec.pict_type != B_TYPE) { + int64_t tmp; + tmp = ist->last_ip_pts; + ist->last_ip_pts = ist->frac_pts.val; + ist->frac_pts.val = tmp; + } + } +#endif + /* if output time reached then transcode raw format, + encode packets and output them */ + if (start_time == 0 || ist->pts >= start_time) + for(i=0;isource_index == ist_index) { + os = output_files[ost->file_index]; + +#if 0 + printf("%d: got pts=%0.3f %0.3f\n", i, + (double)pkt->pts / AV_TIME_BASE, + ((double)ist->pts / AV_TIME_BASE) - + ((double)ost->st->pts.val * os->pts_num / os->pts_den)); +#endif + /* set the input output pts pairs */ + ost->sync_ipts = (double)ist->pts / AV_TIME_BASE; + /* XXX: take into account the various fifos, + in particular for audio */ + ost->sync_opts = ost->st->pts.val; + //printf("ipts=%lld sync_ipts=%f sync_opts=%lld pts.val=%lld pkt->pts=%lld\n", ist->pts, ost->sync_ipts, ost->sync_opts, ost->st->pts.val, pkt->pts); + + if (ost->encoding_needed) { + switch(ost->st->codec.codec_type) { + case CODEC_TYPE_AUDIO: + do_audio_out(os, ost, ist, data_buf, data_size); + break; + case CODEC_TYPE_VIDEO: + /* find an audio stream for synchro */ + { + int i; + AVOutputStream *audio_sync, *ost1; + audio_sync = NULL; + for(i=0;ifile_index == ost->file_index && + ost1->st->codec.codec_type == CODEC_TYPE_AUDIO) { + audio_sync = ost1; + break; + } + } + + do_video_out(os, ost, ist, &picture, &frame_size, audio_sync); + if (do_vstats && frame_size) + do_video_stats(os, ost, frame_size); + } + break; + default: + av_abort(); + } + } else { + AVFrame avframe; + + /* no reencoding needed : output the packet directly */ + /* force the input stream PTS */ + + memset(&avframe, 0, sizeof(AVFrame)); + ost->st->codec.coded_frame= &avframe; + avframe.key_frame = pkt->flags & PKT_FLAG_KEY; + + av_write_frame(os, ost->index, data_buf, data_size); + ost->st->codec.frame_number++; + ost->frame_number++; + } + } + } + av_free(buffer_to_free); + } + discard_packet: + return 0; + fail_decode: + return -1; +} + + /* * The following code is the main loop of the file converter */ @@ -1191,13 +1382,6 @@ static int av_encode(AVFormatContext **output_files, for(; received_sigterm == 0;) { int file_index, ist_index; AVPacket pkt; - uint8_t *ptr; - int len; - uint8_t *data_buf; - int data_size, got_picture; - AVFrame picture; - short samples[AVCODEC_MAX_AUDIO_FRAME_SIZE / 2]; - void *buffer_to_free; double pts_min; redo: @@ -1258,179 +1442,28 @@ static int av_encode(AVFormatContext **output_files, goto discard_packet; //fprintf(stderr,"read #%d.%d size=%d\n", ist->file_index, ist->index, pkt.size); - - if (pkt.pts != AV_NOPTS_VALUE) { - ist->pts = pkt.pts; - } else { - ist->pts = ist->next_pts; - } - - len = pkt.size; - ptr = pkt.data; - while (len > 0) { - /* decode the packet if needed */ - data_buf = NULL; /* fail safe */ - data_size = 0; - if (ist->decoding_needed) { - switch(ist->st->codec.codec_type) { - case CODEC_TYPE_AUDIO: - /* XXX: could avoid copy if PCM 16 bits with same - endianness as CPU */ - ret = avcodec_decode_audio(&ist->st->codec, samples, &data_size, - ptr, len); - if (ret < 0) - goto fail_decode; - ptr += ret; - len -= ret; - /* Some bug in mpeg audio decoder gives */ - /* data_size < 0, it seems they are overflows */ - if (data_size <= 0) { - /* no audio frame */ - continue; - } - data_buf = (uint8_t *)samples; - ist->next_pts += ((int64_t)AV_TIME_BASE * data_size) / - (2 * ist->st->codec.channels); - break; - case CODEC_TYPE_VIDEO: - data_size = (ist->st->codec.width * ist->st->codec.height * 3) / 2; - /* XXX: allocate picture correctly */ - memset(&picture, 0, sizeof(picture)); - ret = avcodec_decode_video(&ist->st->codec, - &picture, &got_picture, ptr, len); - ist->st->quality= picture.quality; - if (ret < 0) { - fail_decode: - fprintf(stderr, "Error while decoding stream #%d.%d\n", - ist->file_index, ist->index); - av_free_packet(&pkt); - goto redo; - } - if (!got_picture) { - /* no picture yet */ - goto discard_packet; - } - if (ist->st->codec.frame_rate_base != 0) { - ist->next_pts += ((int64_t)AV_TIME_BASE * - ist->st->codec.frame_rate_base) / - ist->st->codec.frame_rate; - } - len = 0; - break; - default: - goto fail_decode; - } - } else { - data_buf = ptr; - data_size = len; - ret = len; - len = 0; - } - - buffer_to_free = NULL; - if (ist->st->codec.codec_type == CODEC_TYPE_VIDEO) { - pre_process_video_frame(ist, (AVPicture *)&picture, - &buffer_to_free); - } - - /* frame rate emulation */ - if (ist->st->codec.rate_emu) { - int64_t pts = av_rescale((int64_t) ist->frame * ist->st->codec.frame_rate_base, 1000000, ist->st->codec.frame_rate); - int64_t now = av_gettime() - ist->start; - if (pts > now) - usleep(pts - now); - - ist->frame++; - } - -#if 0 - /* mpeg PTS deordering : if it is a P or I frame, the PTS - is the one of the next displayed one */ - /* XXX: add mpeg4 too ? */ - if (ist->st->codec.codec_id == CODEC_ID_MPEG1VIDEO) { - if (ist->st->codec.pict_type != B_TYPE) { - int64_t tmp; - tmp = ist->last_ip_pts; - ist->last_ip_pts = ist->frac_pts.val; - ist->frac_pts.val = tmp; - } - } -#endif - /* if output time reached then transcode raw format, - encode packets and output them */ - if (start_time == 0 || ist->pts >= start_time) - for(i=0;isource_index == ist_index) { - os = output_files[ost->file_index]; - -#if 0 - printf("%d: got pts=%0.3f %0.3f\n", i, - (double)pkt.pts / AV_TIME_BASE, - ((double)ist->pts / AV_TIME_BASE) - - ((double)ost->st->pts.val * os->pts_num / os->pts_den)); -#endif - /* set the input output pts pairs */ - ost->sync_ipts = (double)ist->pts / AV_TIME_BASE; - /* XXX: take into account the various fifos, - in particular for audio */ - ost->sync_opts = ost->st->pts.val; - //printf("ipts=%lld sync_ipts=%f sync_opts=%lld pts.val=%lld pkt.pts=%lld\n", ist->pts, ost->sync_ipts, ost->sync_opts, ost->st->pts.val, pkt.pts); - - if (ost->encoding_needed) { - switch(ost->st->codec.codec_type) { - case CODEC_TYPE_AUDIO: - do_audio_out(os, ost, ist, data_buf, data_size); - break; - case CODEC_TYPE_VIDEO: - /* find an audio stream for synchro */ - { - int i; - AVOutputStream *audio_sync, *ost1; - audio_sync = NULL; - for(i=0;ifile_index == ost->file_index && - ost1->st->codec.codec_type == CODEC_TYPE_AUDIO) { - audio_sync = ost1; - break; - } - } - - do_video_out(os, ost, ist, &picture, &frame_size, audio_sync); - if (do_vstats && frame_size) - do_video_stats(os, ost, frame_size); - } - break; - default: - av_abort(); - } - } else { - AVFrame avframe; - - /* no reencoding needed : output the packet directly */ - /* force the input stream PTS */ - - memset(&avframe, 0, sizeof(AVFrame)); - ost->st->codec.coded_frame= &avframe; - avframe.key_frame = pkt.flags & PKT_FLAG_KEY; - - av_write_frame(os, ost->index, data_buf, data_size); - ost->st->codec.frame_number++; - ost->frame_number++; - } - } - } - av_free(buffer_to_free); + if (output_packet(ist, ist_index, ost_table, nb_ostreams, &pkt) < 0) { + fprintf(stderr, "Error while decoding stream #%d.%d\n", + ist->file_index, ist->index); + av_free_packet(&pkt); + goto redo; } + discard_packet: av_free_packet(&pkt); /* dump report by using the output first video and audio streams */ print_report(output_files, ost_table, nb_ostreams, 0); } + + /* at the end of stream, we must flush the decoder buffers */ + for(i=0;idecoding_needed) { + output_packet(ist, i, ost_table, nb_ostreams, NULL); + } + } + term_exit(); /* dump report by using the first video and audio streams */