2 Copyright (C) 2011-2013 Robin Gareus <robin@gareus.org>
3 Copyright (C) 2014-2023 Filipe Coelho <falktx@falktx.com>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser Public License as published by
7 the Free Software Foundation; either version 2.1, or (at your option)
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Lesser Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21 #include "ad_plugin.h"
34 #define MIN(a,b) ( ( (a) < (b) )? (a) : (b) )
38 AVFormatContext
* formatContext
;
39 AVCodecContext
* codecContext
;
46 int16_t m_tmpBuffer
[AVCODEC_MAX_AUDIO_FRAME_SIZE
];
47 int16_t* m_tmpBufferStart
;
48 unsigned long m_tmpBufferLen
;
50 int64_t decoder_clock
;
53 unsigned int samplerate
;
54 unsigned int channels
;
56 } ffmpeg_audio_decoder
;
59 static int ad_info_ffmpeg(void *sf
, struct adinfo
*nfo
) {
60 ffmpeg_audio_decoder
*priv
= (ffmpeg_audio_decoder
*) sf
;
63 nfo
->sample_rate
= priv
->samplerate
;
64 nfo
->channels
= priv
->channels
;
65 nfo
->frames
= priv
->length
;
66 if (nfo
->sample_rate
==0) return -1;
67 nfo
->length
= (nfo
->frames
* 1000) / nfo
->sample_rate
;
68 nfo
->bit_rate
= priv
->formatContext
->bit_rate
;
70 nfo
->meta_data
= NULL
;
73 #ifdef WITH_GTK // XXX replace g_* functions with POSIX equiv
74 AVDictionaryEntry
*tag
= NULL
;
76 while ((tag
= av_dict_get(priv
->formatContext
->metadata
, "", tag
, AV_DICT_IGNORE_SUFFIX
))) {
77 dbg(2, "FTAG: %s=%s", tag
->key
, tag
->value
);
78 char * tmp
= g_strdup_printf("%s%s<i>%s</i>:%s", nfo
->meta_data
?nfo
->meta_data
:"",nfo
->meta_data
?"\n":"", tag
->key
, tag
->value
);
79 if (nfo
->meta_data
) g_free(nfo
->meta_data
);
84 AVStream
*stream
= priv
->formatContext
->streams
[priv
->audioStream
];
85 while ((tag
= av_dict_get(stream
->metadata
, "", tag
, AV_DICT_IGNORE_SUFFIX
))) {
86 dbg(2, "STAG: %s=%s", tag
->key
, tag
->value
);
87 char * tmp
= g_strdup_printf("%s%s<i>%s</i>:%s", nfo
->meta_data
?nfo
->meta_data
:"",nfo
->meta_data
?"\n":"", tag
->key
, tag
->value
);
88 if (nfo
->meta_data
) g_free(nfo
->meta_data
);
96 static void *ad_open_ffmpeg(const char *fn
, struct adinfo
*nfo
) {
97 ffmpeg_audio_decoder
*priv
= (ffmpeg_audio_decoder
*) calloc(1, sizeof(ffmpeg_audio_decoder
));
99 priv
->m_tmpBufferStart
=NULL
;
100 priv
->m_tmpBufferLen
=0;
101 priv
->decoder_clock
=priv
->output_clock
=priv
->seek_frame
=0;
102 priv
->packet
.size
=0; priv
->packet
.data
=NULL
;
104 if (avformat_open_input(&priv
->formatContext
, fn
, NULL
, NULL
) <0) {
105 dbg(0, "ffmpeg is unable to open file '%s'.", fn
);
106 free(priv
); return(NULL
);
109 if (avformat_find_stream_info(priv
->formatContext
, NULL
) < 0) {
110 avformat_close_input(&priv
->formatContext
);
111 dbg(0, "av_find_stream_info failed" );
112 free(priv
); return(NULL
);
115 priv
->audioStream
= -1;
117 for (i
=0; i
<priv
->formatContext
->nb_streams
; i
++) {
118 if (priv
->formatContext
->streams
[i
]->codec
->codec_type
== AVMEDIA_TYPE_AUDIO
) {
119 priv
->audioStream
= i
;
123 if (priv
->audioStream
== -1) {
124 dbg(0, "No Audio Stream found in file");
125 avformat_close_input(&priv
->formatContext
);
126 free(priv
); return(NULL
);
129 priv
->codecContext
= priv
->formatContext
->streams
[priv
->audioStream
]->codec
;
130 priv
->codec
= avcodec_find_decoder(priv
->codecContext
->codec_id
);
132 if (priv
->codec
== NULL
) {
133 avformat_close_input(&priv
->formatContext
);
134 dbg(0, "Codec not supported by ffmpeg");
135 free(priv
); return(NULL
);
137 if (avcodec_open2(priv
->codecContext
, priv
->codec
, NULL
) < 0) {
138 dbg(0, "avcodec_open failed" );
139 free(priv
); return(NULL
);
142 dbg(2, "ffmpeg - audio tics: %i/%i [sec]",priv
->formatContext
->streams
[priv
->audioStream
]->time_base
.num
,priv
->formatContext
->streams
[priv
->audioStream
]->time_base
.den
);
144 int64_t len
= priv
->formatContext
->duration
- priv
->formatContext
->start_time
;
146 priv
->formatContext
->flags
|=AVFMT_FLAG_GENPTS
;
147 priv
->formatContext
->flags
|=AVFMT_FLAG_IGNIDX
;
149 priv
->samplerate
= priv
->codecContext
->sample_rate
;
150 priv
->channels
= priv
->codecContext
->channels
;
151 priv
->length
= (int64_t)( len
* priv
->samplerate
/ AV_TIME_BASE
);
153 if (ad_info_ffmpeg((void*)priv
, nfo
)) {
154 dbg(0, "invalid file info (sample-rate==0)");
155 free(priv
); return(NULL
);
158 dbg(1, "ffmpeg - %s", fn
);
160 dbg(1, "ffmpeg - sr:%i c:%i d:%"PRIi64
" f:%"PRIi64
, nfo
->sample_rate
, nfo
->channels
, nfo
->length
, nfo
->frames
);
165 static int ad_close_ffmpeg(void *sf
) {
166 ffmpeg_audio_decoder
*priv
= (ffmpeg_audio_decoder
*) sf
;
167 if (!priv
) return -1;
168 avcodec_close(priv
->codecContext
);
169 avformat_close_input(&priv
->formatContext
);
174 static void int16_to_float(int16_t *in
, float *out
, int num_channels
, int num_samples
, int out_offset
) {
176 for (i
=0;i
<num_samples
;i
++) {
177 for (ii
=0;ii
<num_channels
;ii
++) {
178 out
[(i
+out_offset
)*num_channels
+ii
]= (float) in
[i
*num_channels
+ii
]/ 32768.0;
183 static ssize_t
ad_read_ffmpeg(void *sf
, float* d
, size_t len
) {
184 ffmpeg_audio_decoder
*priv
= (ffmpeg_audio_decoder
*) sf
;
185 if (!priv
) return -1;
186 size_t frames
= len
/ priv
->channels
;
190 while (ret
>= 0 && written
< frames
) {
191 dbg(3,"loop: %i/%i (bl:%lu)",written
, frames
, priv
->m_tmpBufferLen
);
192 if (priv
->seek_frame
== 0 && priv
->m_tmpBufferLen
> 0 ) {
193 int s
= MIN(priv
->m_tmpBufferLen
/ priv
->channels
, frames
- written
);
194 int16_to_float(priv
->m_tmpBufferStart
, d
, priv
->channels
, s
, written
);
196 priv
->output_clock
+=s
;
197 s
= s
* priv
->channels
;
198 priv
->m_tmpBufferStart
+= s
;
199 priv
->m_tmpBufferLen
-= s
;
202 priv
->m_tmpBufferStart
= priv
->m_tmpBuffer
;
203 priv
->m_tmpBufferLen
= 0;
205 if (!priv
->pkt_ptr
|| priv
->pkt_len
<1 ) {
206 if (priv
->packet
.data
) av_free_packet(&priv
->packet
);
207 ret
= av_read_frame(priv
->formatContext
, &priv
->packet
);
208 if (ret
<0) { dbg(1, "reached end of file."); break; }
209 priv
->pkt_len
= priv
->packet
.size
;
210 priv
->pkt_ptr
= priv
->packet
.data
;
213 if (priv
->packet
.stream_index
!= priv
->audioStream
) {
214 priv
->pkt_ptr
= NULL
;
218 /* decode all chunks in packet */
219 int data_size
= AVCODEC_MAX_AUDIO_FRAME_SIZE
;
221 #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(54, 0, 0)
222 // TODO use av_frame_alloc() and av_frame_free() with newer ffmpeg
224 memset(&avf
, 0, sizeof(AVFrame
));
226 ret
= avcodec_decode_audio4(priv
->codecContext
, &avf
, &got_frame
, &priv
->packet
);
227 if (ret
>= 0 && got_frame
) {
229 const int planar
= av_sample_fmt_is_planar(priv
->codecContext
->sample_fmt
);
230 data_size
= av_samples_get_buffer_size(&plane_size
, priv
->codecContext
->channels
, avf
.nb_samples
, priv
->codecContext
->sample_fmt
, 1);
231 if (data_size
<= AVCODEC_MAX_AUDIO_FRAME_SIZE
) {
232 memcpy(priv
->m_tmpBuffer
, avf
.extended_data
[0], plane_size
);
233 if (planar
&& priv
->codecContext
->channels
> 1) {
234 uint8_t *out
= ((uint8_t *)priv
->m_tmpBuffer
) + plane_size
;
235 for (ch
= 1; ch
< priv
->codecContext
->channels
; ch
++) {
236 memcpy(out
, avf
.extended_data
[ch
], plane_size
);
244 #elif LIBAVUTIL_VERSION_INT > AV_VERSION_INT(49, 15, 0) && LIBAVCODEC_VERSION_INT > AV_VERSION_INT(52, 20, 1) // ??
245 // this was deprecated in LIBAVCODEC_VERSION_MAJOR 53
246 ret
= avcodec_decode_audio3(priv
->codecContext
,
247 priv
->m_tmpBuffer
, &data_size
, &priv
->packet
);
249 int len
= priv
->packet
.size
;
250 uint8_t *ptr
= priv
->packet
.data
;
251 ret
= avcodec_decode_audio2(priv
->codecContext
,
252 priv
->m_tmpBuffer
, &data_size
, ptr
, len
);
255 if (ret
< 0 || ret
> priv
->pkt_len
) {
257 dbg(0, "audio decode error");
265 priv
->pkt_len
-= ret
; priv
->pkt_ptr
+= ret
;
267 /* sample exact alignment */
268 if (priv
->packet
.pts
!= AV_NOPTS_VALUE
) {
269 priv
->decoder_clock
= priv
->samplerate
* av_q2d(priv
->formatContext
->streams
[priv
->audioStream
]->time_base
) * priv
->packet
.pts
;
271 dbg(0, "!!! NO PTS timestamp in file");
272 priv
->decoder_clock
+= (data_size
>>1) / priv
->channels
;
276 priv
->m_tmpBufferLen
+= (data_size
>>1); // 2 bytes per sample
279 /* align buffer after seek. */
280 if (priv
->seek_frame
> 0) {
281 const int diff
= priv
->output_clock
-priv
->decoder_clock
;
283 /* seek ended up past the wanted sample */
284 dbg(0, " !!! Audio seek failed.");
286 } else if (priv
->m_tmpBufferLen
< (diff
*priv
->channels
)) {
287 /* wanted sample not in current buffer - keep going */
288 dbg(2, " !!! seeked sample was not in decoded buffer. frames-to-go: %li", diff
);
289 priv
->m_tmpBufferLen
= 0;
290 } else if (diff
!=0 && data_size
> 0) {
291 /* wanted sample is in current buffer but not at the beginnning */
292 dbg(2, " !!! sync buffer to seek. (diff:%i)", diff
);
293 priv
->m_tmpBufferStart
+= diff
*priv
->codecContext
->channels
;
294 priv
->m_tmpBufferLen
-= diff
*priv
->codecContext
->channels
;
296 memmove(priv
->m_tmpBuffer
, priv
->m_tmpBufferStart
, priv
->m_tmpBufferLen
);
297 priv
->m_tmpBufferStart
= priv
->m_tmpBuffer
;
300 priv
->decoder_clock
+= diff
;
301 } else if (data_size
> 0) {
302 dbg(2, "Audio exact sync-seek (%"PRIi64
" == %"PRIi64
")", priv
->decoder_clock
, priv
->seek_frame
);
305 dbg(0, "Error: no audio data in packet");
308 //dbg(0, "PTS: decoder:%"PRIi64". - want: %"PRIi64, priv->decoder_clock, priv->output_clock);
309 //dbg(0, "CLK: frame: %"PRIi64" T:%.3fs",priv->decoder_clock, (float) priv->decoder_clock/priv->samplerate);
312 if (written
!=frames
) {
313 dbg(2, "short-read");
315 return written
* priv
->channels
;
318 static int64_t ad_seek_ffmpeg(void *sf
, int64_t pos
) {
319 ffmpeg_audio_decoder
*priv
= (ffmpeg_audio_decoder
*) sf
;
321 if (pos
== priv
->output_clock
) return pos
;
323 /* flush internal buffer */
324 priv
->m_tmpBufferLen
= 0;
325 priv
->seek_frame
= pos
;
326 priv
->output_clock
= pos
;
327 priv
->pkt_len
= 0; priv
->pkt_ptr
= NULL
;
328 priv
->decoder_clock
= 0;
331 /* TODO seek at least 1 packet before target.
332 * for mpeg compressed files, the
333 * output may depend on past frames! */
334 if (pos
> 8192) pos
-= 8192;
338 const int64_t timestamp
= pos
/ av_q2d(priv
->formatContext
->streams
[priv
->audioStream
]->time_base
) / priv
->samplerate
;
339 dbg(2, "seek frame:%"PRIi64
" - idx:%"PRIi64
, pos
, timestamp
);
341 av_seek_frame(priv
->formatContext
, priv
->audioStream
, timestamp
, AVSEEK_FLAG_ANY
| AVSEEK_FLAG_BACKWARD
);
342 avcodec_flush_buffers(priv
->codecContext
);
346 static int ad_eval_ffmpeg(const char *f
) {
347 char *ext
= strrchr(f
, '.');
349 // libavformat.. guess_format..
354 static const ad_plugin ad_ffmpeg
= {
375 const ad_plugin
* adp_get_ffmpeg() {
377 static int ffinit
= 0;
380 #if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(53, 5, 0)
384 avcodec_register_all();
385 if(ad_debug_level
<= 1)
386 av_log_set_level(AV_LOG_QUIET
);
388 av_log_set_level(AV_LOG_VERBOSE
);