2 * Audio Interleaving functions
4 * Copyright (c) 2009 Baptiste Coudurier <baptiste dot coudurier at gmail dot com>
6 * This file is part of FFmpeg.
8 * FFmpeg is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * FFmpeg is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with FFmpeg; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 #include "libavutil/fifo.h"
24 #include "libavutil/mathematics.h"
26 #include "audiointerleave.h"
29 void ff_audio_interleave_close(AVFormatContext
*s
)
32 for (i
= 0; i
< s
->nb_streams
; i
++) {
33 AVStream
*st
= s
->streams
[i
];
34 AudioInterleaveContext
*aic
= st
->priv_data
;
36 if (st
->codec
->codec_type
== AVMEDIA_TYPE_AUDIO
)
37 av_fifo_freep(&aic
->fifo
);
41 int ff_audio_interleave_init(AVFormatContext
*s
,
42 const int *samples_per_frame
,
47 if (!samples_per_frame
)
48 return AVERROR(EINVAL
);
51 av_log(s
, AV_LOG_ERROR
, "timebase not set for audio interleave\n");
52 return AVERROR(EINVAL
);
54 for (i
= 0; i
< s
->nb_streams
; i
++) {
55 AVStream
*st
= s
->streams
[i
];
56 AudioInterleaveContext
*aic
= st
->priv_data
;
58 if (st
->codec
->codec_type
== AVMEDIA_TYPE_AUDIO
) {
59 aic
->sample_size
= (st
->codec
->channels
*
60 av_get_bits_per_sample(st
->codec
->codec_id
)) / 8;
61 if (!aic
->sample_size
) {
62 av_log(s
, AV_LOG_ERROR
, "could not compute sample size\n");
63 return AVERROR(EINVAL
);
65 aic
->samples_per_frame
= samples_per_frame
;
66 aic
->samples
= aic
->samples_per_frame
;
67 aic
->time_base
= time_base
;
69 aic
->fifo_size
= 100* *aic
->samples
;
70 if (!(aic
->fifo
= av_fifo_alloc_array(100, *aic
->samples
)))
71 return AVERROR(ENOMEM
);
78 static int interleave_new_audio_packet(AVFormatContext
*s
, AVPacket
*pkt
,
79 int stream_index
, int flush
)
81 AVStream
*st
= s
->streams
[stream_index
];
82 AudioInterleaveContext
*aic
= st
->priv_data
;
84 int size
= FFMIN(av_fifo_size(aic
->fifo
), *aic
->samples
* aic
->sample_size
);
85 if (!size
|| (!flush
&& size
== av_fifo_size(aic
->fifo
)))
88 ret
= av_new_packet(pkt
, size
);
91 av_fifo_generic_read(aic
->fifo
, pkt
->data
, size
, NULL
);
93 pkt
->dts
= pkt
->pts
= aic
->dts
;
94 pkt
->duration
= av_rescale_q(*aic
->samples
, st
->time_base
, aic
->time_base
);
95 pkt
->stream_index
= stream_index
;
96 aic
->dts
+= pkt
->duration
;
100 aic
->samples
= aic
->samples_per_frame
;
105 int ff_audio_rechunk_interleave(AVFormatContext
*s
, AVPacket
*out
, AVPacket
*pkt
, int flush
,
106 int (*get_packet
)(AVFormatContext
*, AVPacket
*, AVPacket
*, int),
107 int (*compare_ts
)(AVFormatContext
*, AVPacket
*, AVPacket
*))
112 AVStream
*st
= s
->streams
[pkt
->stream_index
];
113 AudioInterleaveContext
*aic
= st
->priv_data
;
114 if (st
->codec
->codec_type
== AVMEDIA_TYPE_AUDIO
) {
115 unsigned new_size
= av_fifo_size(aic
->fifo
) + pkt
->size
;
116 if (new_size
> aic
->fifo_size
) {
117 if (av_fifo_realloc2(aic
->fifo
, new_size
) < 0)
118 return AVERROR(ENOMEM
);
119 aic
->fifo_size
= new_size
;
121 av_fifo_generic_write(aic
->fifo
, pkt
->data
, pkt
->size
, NULL
);
123 // rewrite pts and dts to be decoded time line position
124 pkt
->pts
= pkt
->dts
= aic
->dts
;
125 aic
->dts
+= pkt
->duration
;
126 if ((ret
= ff_interleave_add_packet(s
, pkt
, compare_ts
)) < 0)
132 for (i
= 0; i
< s
->nb_streams
; i
++) {
133 AVStream
*st
= s
->streams
[i
];
134 if (st
->codec
->codec_type
== AVMEDIA_TYPE_AUDIO
) {
136 while ((ret
= interleave_new_audio_packet(s
, &new_pkt
, i
, flush
)) > 0) {
137 if ((ret
= ff_interleave_add_packet(s
, &new_pkt
, compare_ts
)) < 0)
145 return get_packet(s
, out
, NULL
, flush
);