Merge remote-tracking branch 'qatar/master'

* qatar/master:
  movenc: Write chan atom for all audio tracks in mov mode movies.
  mpegtsenc: use avio_open_dyn_buf(), zero pointers after freeing
  doc/avconv: add some details about the transcoding process.
  avidec: make scale and rate unsigned.
  avconv: check output stream recording time before each frame returned from filters
  avconv: split selecting input file out of transcode().
  avconv: split checking for active outputs out of transcode().
  avfiltergraph: make some functions static.

Conflicts:
	ffmpeg.c
	libavfilter/avfiltergraph.c
	libavfilter/internal.h
	libavformat/mpegtsenc.c
	tests/ref/fate/acodec-alac
	tests/ref/fate/acodec-pcm-s16be
	tests/ref/fate/acodec-pcm-s24be
	tests/ref/fate/acodec-pcm-s32be
	tests/ref/fate/acodec-pcm-s8
	tests/ref/lavf/mov

Merged-by: Michael Niedermayer <michaelni@gmx.at>
This commit is contained in:
Michael Niedermayer 2012-06-04 22:54:15 +02:00
commit 944d049eaa
13 changed files with 231 additions and 133 deletions

View File

@ -79,6 +79,126 @@ The format option may be needed for raw input files.
@c man end DESCRIPTION
@chapter Detailed description
@c man begin DETAILED DESCRIPTION
The transcoding process in @command{ffmpeg} for each output can be described by
the following diagram:
@example
_______ ______________ _________ ______________ ________
| | | | | | | | | |
| input | demuxer | encoded data | decoder | decoded | encoder | encoded data | muxer | output |
| file | ---------> | packets | ---------> | frames | ---------> | packets | -------> | file |
|_______| |______________| |_________| |______________| |________|
@end example
@command{ffmpeg} calls the libavformat library (containing demuxers) to read
input files and get packets containing encoded data from them. When there are
multiple input files, @command{ffmpeg} tries to keep them synchronized by
tracking lowest timestamp on any active input stream.
Encoded packets are then passed to the decoder (unless streamcopy is selected
for the stream, see further for a description). The decoder produces
uncompressed frames (raw video/PCM audio/...) which can be processed further by
filtering (see next section). After filtering the frames are passed to the
encoder, which encodes them and outputs encoded packets again. Finally those are
passed to the muxer, which writes the encoded packets to the output file.
@section Filtering
Before encoding, @command{ffmpeg} can process raw audio and video frames using
filters from the libavfilter library. Several chained filters form a filter
graph. @command{ffmpeg} distinguishes between two types of filtergraphs -
simple and complex.
@subsection Simple filtergraphs
Simple filtergraphs are those that have exactly one input and output, both of
the same type. In the above diagram they can be represented by simply inserting
an additional step between decoding and encoding:
@example
_________ __________ ______________
| | | | | |
| decoded | simple filtergraph | filtered | encoder | encoded data |
| frames | -------------------> | frames | ---------> | packets |
|_________| |__________| |______________|
@end example
Simple filtergraphs are configured with the per-stream @option{-filter} option
(with @option{-vf} and @option{-af} aliases for video and audio respectively).
A simple filtergraph for video can look for example like this:
@example
_______ _____________ _______ _____ ________
| | | | | | | | | |
| input | ---> | deinterlace | ---> | scale | ---> | fps | ---> | output |
|_______| |_____________| |_______| |_____| |________|
@end example
Note that some filters change frame properties but not frame contents. E.g. the
@code{fps} filter in the example above changes number of frames, but does not
touch the frame contents. Another example is the @code{setpts} filter, which
only sets timestamps and otherwise passes the frames unchanged.
@subsection Complex filtergraphs
Complex filtergraphs are those which cannot be described as simply a linear
processing chain applied to one stream. This is the case e.g. when the graph has
more than one input and/or output, or when output stream type is different from
input. They can be represented with the following diagram:
@example
_________
| |
| input 0 |\ __________
|_________| \ | |
\ _________ /| output 0 |
\ | | / |__________|
_________ \| complex | /
| | | |/
| input 1 |---->| filter |\
|_________| | | \ __________
/| graph | \ | |
/ | | \| output 1 |
_________ / |_________| |__________|
| | /
| input 2 |/
|_________|
@end example
Complex filtergraphs are configured with the @option{-filter_complex} option.
Note that this option is global, since a complex filtergraph by its nature
cannot be unambiguously associated with a single stream or file.
A trivial example of a complex filtergraph is the @code{overlay} filter, which
has two video inputs and one video output, containing one video overlaid on top
of the other. Its audio counterpart is the @code{amix} filter.
@section Stream copy
Stream copy is a mode selected by supplying the @code{copy} parameter to the
@option{-codec} option. It makes @command{ffmpeg} omit the decoding and encoding
step for the specified stream, so it does only demuxing and muxing. It is useful
for changing the container format or modifying container-level metadata. The
diagram above will in this case simplify to this:
@example
_______ ______________ ________
| | | | | |
| input | demuxer | encoded data | muxer | output |
| file | ---------> | packets | -------> | file |
|_______| |______________| |________|
@end example
Since there is no decoding or encoding, it is very fast and there is no quality
loss. However it might not work in some cases because of many factors. Applying
filters is obviously also impossible, since filters work on uncompressed data.
@c man end DETAILED DESCRIPTION
@chapter Stream selection
@c man begin STREAM SELECTION

View File

@ -2027,7 +2027,7 @@ static int poll_filters(void)
OutputFile *of = output_files[ost->file_index];
int ret = 0;
if (!ost->filter || ost->is_past_recording_time)
if (!ost->filter)
continue;
if (!ost->filtered_frame && !(ost->filtered_frame = avcodec_alloc_frame())) {
@ -2036,7 +2036,7 @@ static int poll_filters(void)
avcodec_get_frame_defaults(ost->filtered_frame);
filtered_frame = ost->filtered_frame;
while (1) {
while (!ost->is_past_recording_time) {
if (ost->enc->type == AVMEDIA_TYPE_AUDIO &&
!(ost->enc->capabilities & CODEC_CAP_VARIABLE_FRAME_SIZE))
ret = av_buffersink_read_samples(ost->filter->filter, &picref,
@ -3307,6 +3307,57 @@ static int transcode_init(void)
return 0;
}
/**
* @return 1 if there are still streams where more output is wanted,
* 0 otherwise
*/
static int need_output(void)
{
int i;
for (i = 0; i < nb_output_streams; i++) {
OutputStream *ost = output_streams[i];
OutputFile *of = output_files[ost->file_index];
AVFormatContext *os = output_files[ost->file_index]->ctx;
if (ost->is_past_recording_time ||
(os->pb && avio_tell(os->pb) >= of->limit_filesize))
continue;
if (ost->frame_number >= ost->max_frames) {
int j;
for (j = 0; j < of->ctx->nb_streams; j++)
output_streams[of->ost_index + j]->is_past_recording_time = 1;
continue;
}
return 1;
}
return 0;
}
static int select_input_file(uint8_t *no_packet)
{
int64_t ipts_min = INT64_MAX;
int i, file_index = -1;
for (i = 0; i < nb_input_streams; i++) {
InputStream *ist = input_streams[i];
int64_t ipts = ist->pts;
if (ist->discard || no_packet[ist->file_index])
continue;
if (!input_files[ist->file_index]->eof_reached) {
if (ipts < ipts_min) {
ipts_min = ipts;
file_index = ist->file_index;
}
}
}
return file_index;
}
/*
* The following code is the main loop of the file converter
*/
@ -3335,12 +3386,10 @@ static int transcode(void)
timer_start = av_gettime();
for (; received_sigterm == 0;) {
int file_index, ist_index, past_recording_time = 1;
int file_index, ist_index;
AVPacket pkt;
int64_t ipts_min;
int64_t cur_time= av_gettime();
ipts_min = INT64_MAX;
/* if 'q' pressed, exits */
if (!using_stdin) {
static int64_t last_time;
@ -3433,41 +3482,13 @@ static int transcode(void)
}
/* check if there's any stream where output is still needed */
for (i = 0; i < nb_output_streams; i++) {
OutputFile *of;
ost = output_streams[i];
of = output_files[ost->file_index];
os = output_files[ost->file_index]->ctx;
if (ost->is_past_recording_time ||
(os->pb && avio_tell(os->pb) >= of->limit_filesize))
continue;
if (ost->frame_number >= ost->max_frames) {
int j;
for (j = 0; j < of->ctx->nb_streams; j++)
output_streams[of->ost_index + j]->is_past_recording_time = 1;
continue;
}
past_recording_time = 0;
}
if (past_recording_time)
if (!need_output()) {
av_log(NULL, AV_LOG_VERBOSE, "No more output streams to write to, finishing.\n");
break;
/* select the stream that we must read now by looking at the
smallest output pts */
file_index = -1;
for (i = 0; i < nb_input_streams; i++) {
int64_t ipts;
ist = input_streams[i];
ipts = ist->pts;
if (ist->discard || no_packet[ist->file_index])
continue;
if (!input_files[ist->file_index]->eof_reached) {
if (ipts < ipts_min) {
ipts_min = ipts;
file_index = ist->file_index;
}
}
}
/* select the stream that we must read now */
file_index = select_input_file(no_packet);
/* if none, if is finished */
if (file_index < 0) {
if (no_packet_count) {

View File

@ -102,7 +102,15 @@ void avfilter_graph_set_auto_convert(AVFilterGraph *graph, unsigned flags)
graph->disable_auto_convert = flags;
}
int ff_avfilter_graph_check_validity(AVFilterGraph *graph, AVClass *log_ctx)
/**
* Check for the validity of graph.
*
* A graph is considered valid if all its input and output pads are
* connected.
*
* @return 0 in case of success, a negative value otherwise
*/
static int graph_check_validity(AVFilterGraph *graph, AVClass *log_ctx)
{
AVFilterContext *filt;
int i, j;
@ -132,7 +140,12 @@ int ff_avfilter_graph_check_validity(AVFilterGraph *graph, AVClass *log_ctx)
return 0;
}
int ff_avfilter_graph_config_links(AVFilterGraph *graph, AVClass *log_ctx)
/**
* Configure all the links of graphctx.
*
* @return 0 in case of success, a negative value otherwise
*/
static int graph_config_links(AVFilterGraph *graph, AVClass *log_ctx)
{
AVFilterContext *filt;
int i, ret;
@ -688,7 +701,10 @@ static int pick_formats(AVFilterGraph *graph)
return 0;
}
int ff_avfilter_graph_config_formats(AVFilterGraph *graph, AVClass *log_ctx)
/**
* Configure the formats of all the links in the graph.
*/
static int graph_config_formats(AVFilterGraph *graph, AVClass *log_ctx)
{
int ret;
@ -759,11 +775,11 @@ int avfilter_graph_config(AVFilterGraph *graphctx, void *log_ctx)
{
int ret;
if ((ret = ff_avfilter_graph_check_validity(graphctx, log_ctx)))
if ((ret = graph_check_validity(graphctx, log_ctx)))
return ret;
if ((ret = ff_avfilter_graph_config_formats(graphctx, log_ctx)))
if ((ret = graph_config_formats(graphctx, log_ctx)))
return ret;
if ((ret = ff_avfilter_graph_config_links(graphctx, log_ctx)))
if ((ret = graph_config_links(graphctx, log_ctx)))
return ret;
if ((ret = ff_avfilter_graph_config_pointers(graphctx, log_ctx)))
return ret;

View File

@ -44,28 +44,6 @@ typedef struct AVFilterCommand {
struct AVFilterCommand *next;
} AVFilterCommand;
/**
* Check for the validity of graph.
*
* A graph is considered valid if all its input and output pads are
* connected.
*
* @return 0 in case of success, a negative value otherwise
*/
int ff_avfilter_graph_check_validity(AVFilterGraph *graphctx, AVClass *log_ctx);
/**
* Configure all the links of graphctx.
*
* @return 0 in case of success, a negative value otherwise
*/
int ff_avfilter_graph_config_links(AVFilterGraph *graphctx, AVClass *log_ctx);
/**
* Configure the formats of all the links in the graph.
*/
int ff_avfilter_graph_config_formats(AVFilterGraph *graphctx, AVClass *log_ctx);
/**
* Update the position of a link in the age heap.
*/

View File

@ -40,8 +40,8 @@ typedef struct AVIStream {
int remaining;
int packet_size;
int scale;
int rate;
uint32_t scale;
uint32_t rate;
int sample_size; /* size of one sample (or packet) (in the rate/scale sense) in bytes */
int64_t cum_len; /* temporary storage (used during seek) */

View File

@ -422,7 +422,6 @@ static int mov_write_wave_tag(AVIOContext *pb, MOVTrack *track)
} else if (track->enc->codec_id == CODEC_ID_AMR_NB) {
mov_write_amr_tag(pb, track);
} else if (track->enc->codec_id == CODEC_ID_AC3) {
mov_write_chan_tag(pb, track);
mov_write_ac3_tag(pb, track);
} else if (track->enc->codec_id == CODEC_ID_ALAC) {
mov_write_extradata_tag(pb, track);
@ -695,6 +694,9 @@ static int mov_write_audio_tag(AVIOContext *pb, MOVTrack *track)
else if (track->vos_len > 0)
mov_write_glbl_tag(pb, track);
if (track->mode == MODE_MOV && track->enc->codec_type == AVMEDIA_TYPE_AUDIO)
mov_write_chan_tag(pb, track);
return update_size(pb, pos);
}

View File

@ -232,10 +232,6 @@ typedef struct MpegTSWriteStream {
int64_t payload_dts;
int payload_flags;
uint8_t *payload;
uint8_t *adata;
int adata_pos;
int adata_size;
AVFormatContext *amux;
} MpegTSWriteStream;
@ -503,19 +499,6 @@ static void section_write_packet(MpegTSSection *s, const uint8_t *packet)
avio_write(ctx->pb, packet, TS_PACKET_SIZE);
}
/* Write callback for audio packetizer */
static int mpegts_audio_write(void *opaque, uint8_t *buf, int size)
{
MpegTSWriteStream *ts_st = (MpegTSWriteStream *)opaque;
if (ts_st->adata_pos + (int64_t)size > ts_st->adata_size)
return AVERROR(EIO);
memcpy(ts_st->adata + ts_st->adata_pos, buf, size);
ts_st->adata_pos += size;
return 0;
}
static int mpegts_write_header(AVFormatContext *s)
{
MpegTSWrite *ts = s->priv_data;
@ -616,25 +599,11 @@ static int mpegts_write_header(AVFormatContext *s)
st->codec->extradata_size > 0)
{
AVStream *ast;
uint8_t *buffer;
int buffer_size = 32768;
ts_st->amux = avformat_alloc_context();
if (!ts_st->amux) {
ret = AVERROR(ENOMEM);
goto fail;
}
buffer = av_malloc(buffer_size);
if (!buffer) {
ret = AVERROR(ENOMEM);
goto fail;
}
ts_st->amux->pb = avio_alloc_context(buffer, buffer_size, AVIO_FLAG_WRITE,
ts_st, NULL, mpegts_audio_write, NULL);
if (!ts_st->amux->pb) {
av_free(buffer);
ret = AVERROR(ENOMEM);
goto fail;
}
ts_st->amux->oformat = av_guess_format((ts->flags & MPEGTS_FLAG_AAC_LATM) ? "latm" : "adts", NULL, NULL);
if (!ts_st->amux->oformat) {
ret = AVERROR(EINVAL);
@ -723,8 +692,6 @@ static int mpegts_write_header(AVFormatContext *s)
if (ts_st) {
av_freep(&ts_st->payload);
if (ts_st->amux) {
av_freep(&ts_st->amux->pb->buffer);
av_freep(&ts_st->amux->pb);
avformat_free_context(ts_st->amux);
ts_st->amux = NULL;
}
@ -1130,24 +1097,20 @@ static int mpegts_write_packet_internal(AVFormatContext *s, AVPacket *pkt)
av_init_packet(&pkt2);
pkt2.data = pkt->data;
pkt2.size = pkt->size;
ts_st->adata_size = 1024 + pkt->size;
ts_st->adata = data = av_malloc(ts_st->adata_size);
ts_st->adata_pos = 0;
if (!data)
ret = avio_open_dyn_buf(&ts_st->amux->pb);
if (ret < 0)
return AVERROR(ENOMEM);
ret = av_write_frame(ts_st->amux, &pkt2);
if (ret < 0) {
avio_close_dyn_buf(ts_st->amux->pb, &data);
ts_st->amux->pb = NULL;
av_free(data);
return ret;
}
avio_flush(ts_st->amux->pb);
if (ts_st->amux->pb->error < 0) {
av_free(data);
return ts_st->amux->pb->error;
}
buf = ts_st->adata;
size = ts_st->adata_pos;
size = avio_close_dyn_buf(ts_st->amux->pb, &data);
ts_st->amux->pb = NULL;
buf = data;
}
}
@ -1236,8 +1199,6 @@ static int mpegts_write_end(AVFormatContext *s)
MpegTSWriteStream *ts_st = st->priv_data;
av_freep(&ts_st->payload);
if (ts_st->amux) {
av_freep(&ts_st->amux->pb->buffer);
av_freep(&ts_st->amux->pb);
avformat_free_context(ts_st->amux);
ts_st->amux = NULL;
}

View File

@ -1,4 +1,4 @@
1e5266b204b33ab4608e368d309716cb *tests/data/fate/acodec-alac.mov
388994 tests/data/fate/acodec-alac.mov
f01f453dd13c4e88266409cddf2a7177 *tests/data/fate/acodec-alac.mov
389018 tests/data/fate/acodec-alac.mov
64151e4bcc2b717aa5a8454d424d6a1f *tests/data/fate/acodec-alac.out.wav
stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 1058400/ 1058400

View File

@ -1,4 +1,4 @@
a874f5c08b8d104a6bbf41b21454180d *tests/data/fate/acodec-pcm-s16be.mov
1059045 tests/data/fate/acodec-pcm-s16be.mov
8bffa66afe9e17366af11e77882518a0 *tests/data/fate/acodec-pcm-s16be.mov
1059069 tests/data/fate/acodec-pcm-s16be.mov
64151e4bcc2b717aa5a8454d424d6a1f *tests/data/fate/acodec-pcm-s16be.out.wav
stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 1058400/ 1058400

View File

@ -1,4 +1,4 @@
833d4afd907139af7106a5642a9c23d3 *tests/data/fate/acodec-pcm-s24be.mov
1588245 tests/data/fate/acodec-pcm-s24be.mov
e3013cfce9b792acb9d572268012160d *tests/data/fate/acodec-pcm-s24be.mov
1588269 tests/data/fate/acodec-pcm-s24be.mov
64151e4bcc2b717aa5a8454d424d6a1f *tests/data/fate/acodec-pcm-s24be.out.wav
stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 1058400/ 1058400

View File

@ -1,4 +1,4 @@
c02c96e37b321f2c978968e3a102c669 *tests/data/fate/acodec-pcm-s32be.mov
2117449 tests/data/fate/acodec-pcm-s32be.mov
f3ef00480e89c5c791e87b8af1cc167c *tests/data/fate/acodec-pcm-s32be.mov
2117473 tests/data/fate/acodec-pcm-s32be.mov
64151e4bcc2b717aa5a8454d424d6a1f *tests/data/fate/acodec-pcm-s32be.out.wav
stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 1058400/ 1058400

View File

@ -1,4 +1,4 @@
111d465266385298fde83005402ac171 *tests/data/fate/acodec-pcm-s8.mov
529829 tests/data/fate/acodec-pcm-s8.mov
2c504a4e48c19ea1b0e1705893b771bf *tests/data/fate/acodec-pcm-s8.mov
529853 tests/data/fate/acodec-pcm-s8.mov
651d4eb8d98dfcdda96ae6c43d8f156b *tests/data/fate/acodec-pcm-s8.out.wav
stddev: 147.89 PSNR: 52.93 MAXDIFF: 255 bytes: 1058400/ 1058400

View File

@ -1,12 +1,12 @@
83754d7142a7770ac374f75b729a9319 *./tests/data/lavf/lavf.mov
367322 ./tests/data/lavf/lavf.mov
484aeef3be3eb4deef05c83bdc2dd484 *./tests/data/lavf/lavf.mov
367346 ./tests/data/lavf/lavf.mov
./tests/data/lavf/lavf.mov CRC=0x2f6a9b26
9a0b239ff596da58debcf210dece3985 *./tests/data/lavf/lavf.mov
357821 ./tests/data/lavf/lavf.mov
305a68397e3cdb505704841fedcdc352 *./tests/data/lavf/lavf.mov
357845 ./tests/data/lavf/lavf.mov
./tests/data/lavf/lavf.mov CRC=0x2f6a9b26
cea874222a6d40b1761d75ea11ebe681 *./tests/data/lavf/lavf.mov
367251 ./tests/data/lavf/lavf.mov
6e047bce400f2c4a840f783dee1ae030 *./tests/data/lavf/lavf.mov
367275 ./tests/data/lavf/lavf.mov
./tests/data/lavf/lavf.mov CRC=0xab307eb9
9a0b239ff596da58debcf210dece3985 *./tests/data/lavf/lavf.mov
357821 ./tests/data/lavf/lavf.mov
305a68397e3cdb505704841fedcdc352 *./tests/data/lavf/lavf.mov
357845 ./tests/data/lavf/lavf.mov
./tests/data/lavf/lavf.mov CRC=0x2f6a9b26