1 /* This is a DEPRECATED code used only to maintain */
2 /* compatibility with libavresample for installations */
3 /* that don't have access to libswresample. Upgrading */
4 /* to swresample is HIGHLY recommended, as this code */
5 /* is most likely to lead to imprecise results */
6
7 #include <libavresample/avresample.h>
8 #include <libavutil/opt.h>
9
10 #include "bliss.h"
11
12 #define NB_BYTES_PER_SAMPLE 2
13 #define SAMPLE_RATE 22050
14
av_calloc(size_t nmemb,size_t size)15 void *av_calloc(size_t nmemb, size_t size) {
16 if (size <= 0 || nmemb >= INT_MAX / size)
17 return NULL;
18 return av_mallocz(nmemb * size);
19 }
20
av_samples_fill_arrays_fixed(uint8_t ** audio_data,int * linesize,const uint8_t * buf,int nb_channels,int nb_samples,enum AVSampleFormat sample_fmt,int align)21 int av_samples_fill_arrays_fixed(uint8_t **audio_data, int *linesize,
22 const uint8_t *buf, int nb_channels,
23 int nb_samples, enum AVSampleFormat sample_fmt,
24 int align) {
25 int ch, planar, buf_size, line_size;
26
27 planar = av_sample_fmt_is_planar(sample_fmt);
28 buf_size = av_samples_get_buffer_size(&line_size, nb_channels, nb_samples,
29 sample_fmt, align);
30 if (buf_size < 0)
31 return buf_size;
32
33 audio_data[0] = (uint8_t *)buf;
34 for (ch = 1; planar && ch < nb_channels; ch++)
35 audio_data[ch] = audio_data[ch - 1] + line_size;
36
37 if (linesize)
38 *linesize = line_size;
39
40 return buf_size;
41 }
42
av_samples_alloc_fixed(uint8_t ** audio_data,int * linesize,int nb_channels,int nb_samples,enum AVSampleFormat sample_fmt,int align)43 int av_samples_alloc_fixed(uint8_t **audio_data, int *linesize, int nb_channels,
44 int nb_samples, enum AVSampleFormat sample_fmt,
45 int align) {
46 uint8_t *buf;
47 int size = av_samples_get_buffer_size(NULL, nb_channels, nb_samples,
48 sample_fmt, align);
49 if (size < 0)
50 return size;
51
52 buf = av_malloc(size);
53 if (!buf)
54 return AVERROR(ENOMEM);
55
56 size = av_samples_fill_arrays_fixed(audio_data, linesize, buf, nb_channels,
57 nb_samples, sample_fmt, align);
58 if (size < 0) {
59 av_free(buf);
60 return size;
61 }
62
63 av_samples_set_silence(audio_data, 0, nb_samples, nb_channels, sample_fmt);
64
65 return size;
66 }
67
av_samples_alloc_array_and_samples_fixed(uint8_t *** audio_data,int * linesize,int nb_channels,int nb_samples,enum AVSampleFormat sample_fmt,int align)68 int av_samples_alloc_array_and_samples_fixed(uint8_t ***audio_data,
69 int *linesize, int nb_channels,
70 int nb_samples,
71 enum AVSampleFormat sample_fmt,
72 int align) {
73 int ret, nb_planes = av_sample_fmt_is_planar(sample_fmt) ? nb_channels : 1;
74
75 *audio_data = av_calloc(nb_planes, sizeof(**audio_data));
76 if (!*audio_data)
77 return AVERROR(ENOMEM);
78 ret = av_samples_alloc_fixed(*audio_data, linesize, nb_channels, nb_samples,
79 sample_fmt, align);
80 if (ret < 0)
81 av_freep(audio_data);
82 return ret;
83 }
84
bl_audio_decode(char const * const filename,struct bl_song * const song)85 int bl_audio_decode(char const *const filename, struct bl_song *const song) {
86 int ret;
87 // Contexts and libav variables
88 AVPacket avpkt;
89 AVFormatContext *context;
90 int audio_stream;
91 AVCodecContext *codec_context = NULL;
92 AVCodec *codec = NULL;
93 AVFrame *decoded_frame = NULL;
94 AVAudioResampleContext *avr_ctx;
95
96 // Size of the samples
97 uint64_t size = 0;
98
99 // Dictionary to fetch tags
100 AVDictionaryEntry *tags_dictionary;
101
102 // Pointer to beginning of music data
103 int8_t *beginning;
104 // Received frame holder
105 int got_frame;
106 // Position in the data buffer
107 int index;
108 // Initialize AV lib
109 av_register_all();
110 context = avformat_alloc_context();
111
112 av_log_set_level(AV_LOG_QUIET);
113
114 // Open input file
115 if (avformat_open_input(&context, filename, NULL, NULL) < 0) {
116 fprintf(stderr, "Couldn't open file: %s. Error %d encountered.\n", filename,
117 errno);
118 return BL_UNEXPECTED;
119 }
120
121 // Search for a valid stream
122 if (avformat_find_stream_info(context, NULL) < 0) {
123 fprintf(stderr, "Couldn't find stream information\n");
124 return BL_UNEXPECTED;
125 }
126
127 // Get audio stream
128 audio_stream =
129 av_find_best_stream(context, AVMEDIA_TYPE_AUDIO, -1, -1, &codec, 0);
130 if (audio_stream < 0) {
131 fprintf(stderr, "Couldn't find a suitable audio stream\n");
132 return BL_UNEXPECTED;
133 }
134
135 // Find associated codec
136 codec_context = context->streams[audio_stream]->codec;
137 if (!codec_context) {
138 fprintf(stderr, "Codec not found!\n");
139 return BL_UNEXPECTED;
140 }
141 if (avcodec_open2(codec_context, codec, NULL) < 0) {
142 fprintf(stderr, "Could not open codec\n");
143 return BL_UNEXPECTED;
144 }
145 // Fill song properties
146 song->filename = malloc(strlen(filename) + 1);
147 strcpy(song->filename, filename);
148
149 song->sample_rate = codec_context->sample_rate;
150 song->duration = (uint64_t)(context->duration) / ((uint64_t)AV_TIME_BASE);
151 song->bitrate = context->bit_rate;
152 song->resampled = 0;
153 song->nb_bytes_per_sample =
154 av_get_bytes_per_sample(codec_context->sample_fmt);
155 song->channels = codec_context->channels;
156
157 // Get number of samples
158 size = (((uint64_t)(context->duration) * (uint64_t)SAMPLE_RATE) /
159 ((uint64_t)AV_TIME_BASE)) *
160 song->channels * NB_BYTES_PER_SAMPLE;
161
162 // Estimated number of samples
163 song->nSamples = ((((uint64_t)(context->duration) * (uint64_t)SAMPLE_RATE) /
164 ((uint64_t)AV_TIME_BASE)) *
165 song->channels);
166
167 // Allocate sample_array
168 if ((song->sample_array = calloc(size, 1)) == NULL) {
169 fprintf(stderr, "Could not allocate enough memory\n");
170 return BL_UNEXPECTED;
171 }
172
173 beginning = song->sample_array;
174 index = 0;
175
176 song->resampled = 0;
177 song->nb_bytes_per_sample =
178 av_get_bytes_per_sample(codec_context->sample_fmt);
179 song->channels = codec_context->channels;
180
181 // If the song is in a floating-point format, prepare the conversion to int16
182 if (codec_context->sample_fmt != AV_SAMPLE_FMT_S16 ||
183 (codec_context->sample_rate != SAMPLE_RATE)) {
184 song->resampled = 1;
185 song->nb_bytes_per_sample = 2;
186 song->sample_rate = SAMPLE_RATE;
187
188 avr_ctx = avresample_alloc_context();
189 if (codec_context->channel_layout <= 0) {
190 fprintf(stderr,
191 "Impossible to find channel layout; assuming stereo...\n");
192 av_opt_set_int(avr_ctx, "in_channel_layout", AV_CH_LAYOUT_STEREO, 0);
193 av_opt_set_int(avr_ctx, "out_channel_layout", AV_CH_LAYOUT_STEREO, 0);
194 } else {
195 av_opt_set_int(avr_ctx, "in_channel_layout",
196 codec_context->channel_layout, 0);
197 av_opt_set_int(avr_ctx, "out_channel_layout",
198 codec_context->channel_layout, 0);
199 }
200 av_opt_set_int(avr_ctx, "in_sample_rate", codec_context->sample_rate, 0);
201 av_opt_set_int(avr_ctx, "in_sample_fmt", codec_context->sample_fmt, 0);
202
203 av_opt_set_int(avr_ctx, "out_sample_rate", song->sample_rate, 0);
204 av_opt_set_int(avr_ctx, "out_sample_fmt", AV_SAMPLE_FMT_S16, 0);
205 if ((ret = avresample_open(avr_ctx)) < 0) {
206 fprintf(stderr, "Could not allocate resampler context\n");
207 return BL_UNEXPECTED;
208 }
209 }
210
211 // Zero initialize tags
212 song->artist = NULL;
213 song->title = NULL;
214 song->album = NULL;
215 song->tracknumber = NULL;
216
217 // Initialize tracknumber tag
218 tags_dictionary = av_dict_get(context->metadata, "track", NULL, 0);
219 if (tags_dictionary != NULL) {
220 song->tracknumber = malloc(strlen(tags_dictionary->value) + 1);
221 strcpy(song->tracknumber, tags_dictionary->value);
222 song->tracknumber[strcspn(song->tracknumber, "/")] = '\0';
223 } else {
224 song->tracknumber = malloc(1 * sizeof(char));
225 strcpy(song->tracknumber, "");
226 }
227
228 // Initialize title tag
229 tags_dictionary = av_dict_get(context->metadata, "title", NULL, 0);
230 if (tags_dictionary != NULL) {
231 song->title = malloc(strlen(tags_dictionary->value) + 1);
232 strcpy(song->title, tags_dictionary->value);
233 } else {
234 song->title = malloc(12 * sizeof(char));
235 strcpy(song->title, "<no title>");
236 }
237
238 // Initialize artist tag
239 tags_dictionary = av_dict_get(context->metadata, "ARTIST", NULL, 0);
240 if (tags_dictionary != NULL) {
241 song->artist = malloc(strlen(tags_dictionary->value) + 1);
242 strcpy(song->artist, tags_dictionary->value);
243 } else {
244 song->artist = malloc(12 * sizeof(char));
245 strcpy(song->artist, "<no artist>");
246 }
247
248 // Initialize album tag
249 tags_dictionary = av_dict_get(context->metadata, "ALBUM", NULL, 0);
250 if (tags_dictionary != NULL) {
251 song->album = malloc(strlen(tags_dictionary->value) + 1);
252 strcpy(song->album, tags_dictionary->value);
253 } else {
254 song->album = malloc(11 * sizeof(char));
255 strcpy(song->album, "<no album>");
256 }
257
258 // Initialize genre tag
259 tags_dictionary = av_dict_get(context->metadata, "genre", NULL, 0);
260 if (tags_dictionary != NULL) {
261 song->genre = malloc(strlen(tags_dictionary->value) + 1);
262 strcpy(song->genre, tags_dictionary->value);
263 } else {
264 song->genre = malloc(11 * sizeof(char));
265 strcpy(song->genre, "<no genre>");
266 }
267
268 // Read the whole data and copy them into a huge buffer
269 av_init_packet(&avpkt);
270 while (av_read_frame(context, &avpkt) >= 0) {
271 if (avpkt.stream_index == audio_stream) {
272 got_frame = 0;
273
274 // If decoded frame has not been allocated yet
275 if (!decoded_frame) {
276 // Try to allocate it
277 decoded_frame = av_frame_alloc();
278 if (!decoded_frame) {
279 fprintf(stderr, "Could not allocate audio frame\n");
280 return BL_UNEXPECTED;
281 }
282 } else {
283 // Else, unreference it and reset fields
284 av_frame_unref(decoded_frame);
285 }
286
287 int length = avcodec_decode_audio4(codec_context, decoded_frame,
288 &got_frame, &avpkt);
289 if (length < 0) {
290 avpkt.size = 0;
291 }
292
293 av_free_packet(&avpkt);
294
295 // Copy decoded data into a huge array
296 if (got_frame) {
297 size_t data_size = av_samples_get_buffer_size(
298 NULL, codec_context->channels, decoded_frame->nb_samples,
299 codec_context->sample_fmt, 1);
300
301 if ((index * song->nb_bytes_per_sample + data_size) > size) {
302 int8_t *ptr;
303 ptr = realloc(beginning, size + data_size);
304 if (ptr != NULL) {
305 beginning = ptr;
306 size += data_size;
307 song->nSamples += data_size / song->nb_bytes_per_sample;
308 } else
309 break;
310 }
311
312 // If the song is in a floating-point format, convert it to int16
313 if (song->resampled == 1) {
314 uint8_t **out_buffer;
315 size_t dst_bufsize;
316 // Approximate the resampled buffer size
317 int dst_nb_samples = av_rescale_rnd(
318 avresample_get_delay(avr_ctx) + decoded_frame->nb_samples,
319 SAMPLE_RATE, codec_context->sample_rate, AV_ROUND_UP);
320
321 dst_bufsize = av_samples_alloc_array_and_samples_fixed(
322 &out_buffer, decoded_frame->linesize, song->channels,
323 dst_nb_samples, AV_SAMPLE_FMT_S16, 0);
324
325 ret = avresample_convert(avr_ctx, out_buffer, 0, dst_bufsize,
326 (uint8_t **)decoded_frame->extended_data, 0,
327 decoded_frame->nb_samples);
328
329 if (ret < 0) {
330 fprintf(stderr,
331 "Error while converting from floating-point to int\n");
332 return BL_UNEXPECTED;
333 }
334 if (ret != 0) {
335 // Get the real resampled buffer size
336 dst_bufsize = av_samples_get_buffer_size(NULL, song->channels, ret,
337 AV_SAMPLE_FMT_S16, 1);
338 memcpy((index * song->nb_bytes_per_sample) + beginning,
339 out_buffer[0], dst_bufsize);
340 index += dst_bufsize / (float)song->nb_bytes_per_sample;
341 }
342 av_freep(&out_buffer[0]);
343 free(out_buffer);
344 } else {
345 memcpy((index * song->nb_bytes_per_sample) + beginning,
346 decoded_frame->extended_data[0], data_size);
347 index += data_size / song->nb_bytes_per_sample;
348 }
349 }
350 } else {
351 // Dropping packets that do not belong to the audio stream
352 // (such as album cover)
353 av_free_packet(&avpkt);
354 }
355 }
356 song->sample_array = beginning;
357
358 // Free memory
359 avpkt.data = NULL;
360 avpkt.size = 0;
361
362 // Use correct number of samples after decoding
363 song->nSamples = index;
364
365 // Read the end of audio, as precognized in
366 // http://ffmpeg.org/pipermail/libav-user/2015-August/008433.html
367 do {
368 avcodec_decode_audio4(codec_context, decoded_frame, &got_frame, &avpkt);
369 } while (got_frame);
370
371 // Free memory
372 if (song->resampled)
373 avresample_free(&avr_ctx);
374 avcodec_close(codec_context);
375 av_frame_unref(decoded_frame);
376 #if LIBAVUTIL_VERSION_MAJOR > 51
377 av_frame_free(&decoded_frame);
378 #endif
379 av_free_packet(&avpkt);
380 avformat_close_input(&context);
381
382 return BL_OK;
383 }
384