OSDN Git Service

[Qt][WIN32] Move config and logger to inner pointer, now, libCSPavio is separated...
[csp-qt/common_source_project-fm7.git] / source / src / qt / avio / sound_loader.cpp
1 /*
2  * Common Source Code Project for Qt : movie saver.
3  * (C) 2016 K.Ohta <whatisthis.sowhat _at_ gmail.com>
4  *  License: GPLv2
5  *  History: Oct 02, 2016 : Initial. 
6  */
7
8 #include "csp_logger.h"
9 #include "sound_loader.h"
10 #include "../osd_base.h"
11
12 SOUND_LOADER::SOUND_LOADER(void *prev_sound_loader, CSP_Logger *logger)
13 {
14         _filename.clear();
15         _dst_size = _dataptr = 0;
16         _data[0] = _data[1] = _data[2] = _data[3] = NULL;
17         sound_buffer = NULL;
18         _data_size = 0;
19         sound_rate = 48000;
20         this_id = -1;
21         
22         prev_loader = prev_sound_loader;
23         p_logger = logger;
24 #if defined(USE_LIBAV)
25         fmt_ctx = NULL;
26         audio_dec_ctx = NULL;
27         swr_context = NULL;
28         audio_stream = NULL;
29         audio_stream_idx = -1;
30         frame = NULL;
31 #endif
32 }
33
34 SOUND_LOADER::~SOUND_LOADER()
35 {
36         if(sound_buffer != NULL) free(sound_buffer);
37         for(int i = 0; i < 4; i++) {
38                 if(_data[i] != NULL) free(_data);
39         }
40 }
41
42 bool SOUND_LOADER::open(int id, QString filename)
43 {
44         int ret = 0;
45         _filename = filename;
46         if(filename.isEmpty()) {
47                 return false;
48         }
49         _dst_size = 0;
50         _data_size = 0;
51         _dataptr = 0;
52         /* register all formats and codecs */
53         av_register_all();
54         
55         /* open input file, and allocate format context */
56         if (avformat_open_input(&fmt_ctx, _filename.toLocal8Bit().constData(), NULL, NULL) < 0) {
57                 p_logger->debug_log(CSP_LOG_INFO, CSP_LOG_TYPE_SOUND_LOADER, "Could not open source file %s\n", _filename.toLocal8Bit().constData());
58         return false;
59         }
60         this_id = id;
61         /* retrieve stream information */
62         if (avformat_find_stream_info(fmt_ctx, NULL) < 0) {
63                 p_logger->debug_log(CSP_LOG_INFO, CSP_LOG_TYPE_SOUND_LOADER, "Could not find stream information\n");
64                 return false;
65         }
66         if (open_codec_context(&audio_stream_idx, fmt_ctx, AVMEDIA_TYPE_AUDIO) >= 0) {
67                 audio_stream = fmt_ctx->streams[audio_stream_idx];
68                 audio_dec_ctx = audio_stream->codec;
69                 //sound_rate = audio_stream->codec->sample_rate;
70         }
71         swr_context = swr_alloc();
72         if(swr_context == NULL) {
73                 p_logger->debug_log(CSP_LOG_INFO, CSP_LOG_TYPE_SOUND_LOADER, "Could not allocate resampler context\n");
74                 goto _end;
75         }
76         av_opt_set_int     (swr_context, "in_channel_count",   audio_stream->codec->channels,      0);
77         av_opt_set_int     (swr_context, "in_sample_rate",         audio_stream->codec->sample_rate,    0);
78         av_opt_set_sample_fmt(swr_context, "in_sample_fmt",        audio_stream->codec->sample_fmt, 0);
79         av_opt_set_int     (swr_context, "out_channel_count",  2,          0);
80         av_opt_set_int     (swr_context, "out_sample_rate",        sound_rate,  0);
81         av_opt_set_sample_fmt(swr_context, "out_sample_fmt",   AV_SAMPLE_FMT_S16,        0);
82         
83         /* initialize the resampling context */
84         if ((ret = swr_init(swr_context)) < 0) {
85                 p_logger->debug_log(CSP_LOG_INFO, CSP_LOG_TYPE_SOUND_LOADER, "Failed to initialize the resampling context\n");
86                 goto _end;
87         }
88         
89         /* dump input information to stderr */
90         av_dump_format(fmt_ctx, 0, _filename.toLocal8Bit().constData(), 0);
91         p_logger->debug_log(CSP_LOG_INFO, CSP_LOG_TYPE_SOUND_LOADER, "Audio is %d Hz ", sound_rate);
92         if (!audio_stream) {
93                 p_logger->debug_log(CSP_LOG_INFO, CSP_LOG_TYPE_SOUND_LOADER, "Could not find audio or video stream in the input, aborting\n");
94                 ret = 1;
95                 goto _end;
96         }
97         frame = av_frame_alloc();
98         if (!frame) {
99                 p_logger->debug_log(CSP_LOG_INFO, CSP_LOG_TYPE_SOUND_LOADER, "Could not allocate frame\n");
100                 ret = AVERROR(ENOMEM);
101                 goto _end;
102         }
103         
104         /* initialize packet, set data to NULL, let the demuxer fill it */
105         av_init_packet(&pkt);
106         pkt.data = NULL;
107         pkt.size = 0;
108         // ToDo : Initialize SWScaler and SWresampler.
109         p_logger->debug_log(CSP_LOG_INFO, CSP_LOG_TYPE_SOUND_LOADER, "SOUND_LOADER: Loading movie completed.\n");
110         return true;
111 _end:
112         this->close();
113         return false;
114 }
115
116 void SOUND_LOADER::close(void)
117 {
118 #if defined(USE_LIBAV)
119         if(audio_dec_ctx != NULL) avcodec_close(audio_dec_ctx);
120         avformat_close_input(&fmt_ctx);
121         swr_free(&swr_context);
122         
123         fmt_ctx = NULL;
124         audio_dec_ctx = NULL;
125         swr_context = NULL;
126         audio_stream = NULL;
127         audio_stream_idx = -1;
128         frame = NULL;
129 #endif
130         for(int i = 0; i < 4; i++) {
131                 if(_data[i] != NULL) free(_data[i]);
132                 _data[i] = NULL;
133         }
134         p_logger->debug_log(CSP_LOG_INFO, CSP_LOG_TYPE_SOUND_LOADER, "SOUND_LOADER: Close sound.");
135 }
136
137 #if defined(USE_LIBAV)  
138 int SOUND_LOADER::decode_packet(int *got_frame, int cached)
139 {
140         int ret = 0;
141         int decoded = pkt.size;
142
143         if (pkt.stream_index == audio_stream_idx) {
144                 ret = avcodec_decode_audio4(audio_dec_ctx, frame, got_frame, &pkt);
145                 if (ret < 0) {
146                         char str_buf[AV_ERROR_MAX_STRING_SIZE] = {0};
147                         av_make_error_string(str_buf, AV_ERROR_MAX_STRING_SIZE, ret);
148                         p_logger->debug_log(CSP_LOG_INFO, CSP_LOG_TYPE_SOUND_LOADER, "Error decoding audio frame (%s)\n", str_buf);
149                         return ret;
150                 }
151                 /* Some audio decoders decode only part of the packet, and have to be
152                  * called again with the remainder of the packet data.
153                  * Sample: fate-suite/lossless-audio/luckynight-partial.shn
154                  * Also, some decoders might over-read the packet. */
155                 decoded = FFMIN(ret, pkt.size);
156                         
157                 if (*got_frame) {
158                         //size_t unpadded_linesize = frame->nb_samples * av_get_bytes_per_sample((enum AVSampleFormat)frame->format);
159                         //char str_buf[AV_TS_MAX_STRING_SIZE] = {0};
160                         AVCodecContext *c = audio_stream->codec;
161                         int dst_nb_samples = av_rescale_rnd(swr_get_delay(swr_context, c->sample_rate) + frame->nb_samples,
162                                                                                                 c->sample_rate, c->sample_rate,  AV_ROUND_UP);
163                         //av_ts_make_time_string(str_buf, frame->pts, &audio_dec_ctx->time_base);
164                         //p_logger->debug_log(CSP_LOG_DEBUG, CSP_LOG_TYPE_SOUND_LOADER,"audio_frame%s n:%d nb_samples:%d pts:%s\n",
165                         //                        cached ? "(cached)" : "",
166                         //                        audio_frame_count++, frame->nb_samples,
167                         //                        str_buf);
168                         /* Write the raw audio data samples of the first plane. This works
169                          * fine for packed formats (e.g. AV_SAMPLE_FMT_S16). However,
170                          * most audio decoders output planar audio, which uses a separate
171                          * plane of audio samples for each channel (e.g. AV_SAMPLE_FMT_S16P).
172                          * In other words, this code will write only the first audio channel
173                          * in these cases.
174                          * You should use libswresample or libavfilter to convert the frame
175                          * to packed data. */
176                         _data[0] = (uint8_t *)malloc((long)dst_nb_samples * 2 * sizeof(int16_t));
177                         _data[1] = _data[2] = _data[3] = NULL;
178                         if(_data[0] == NULL) {
179                                 p_logger->debug_log(CSP_LOG_INFO, CSP_LOG_TYPE_SOUND_LOADER, "Error allocating local buffers\n");
180                                 return -1;
181                         }
182                                 
183                         ret = swr_convert(swr_context,
184                                                           _data, dst_nb_samples,
185                                                           (const uint8_t **)frame->data, frame->nb_samples);
186                         if (ret < 0) {
187                                 p_logger->debug_log(CSP_LOG_INFO, CSP_LOG_TYPE_SOUND_LOADER, "Error while converting\n");
188                                 return -1;
189                         }
190                         _dst_size += dst_nb_samples;
191                         if(_data_size <= (uint)(_dst_size * 2 * sizeof(int16_t))) {
192                                 sound_buffer = (int16_t *)realloc(sound_buffer, _data_size << 1);
193                                 if(sound_buffer == NULL) {
194                                         p_logger->debug_log(CSP_LOG_INFO, CSP_LOG_TYPE_SOUND_LOADER, "Error re-allocate sound buffer");
195                                         if(_data[0] != NULL) free(_data[0]);
196                                         _data[0] = NULL;
197                                         return -1;
198                                 }
199                                 _data_size <<= 1;
200                         }
201                         my_memcpy(&sound_buffer[_dataptr], _data[0], (long)dst_nb_samples * 2 * sizeof(int16_t));
202                         _dataptr += (dst_nb_samples * 2);
203                         free(_data[0]);
204                         _data[0] = NULL;
205                 }
206         } else {
207                 // Video
208                 return 0;
209         }
210         /* If we use frame reference counting, we own the data and need
211          * to de-reference it when we don't use it anymore */
212         if (*got_frame)
213                 av_frame_unref(frame);
214         return decoded;
215 }
216
217 int SOUND_LOADER::open_codec_context(int *stream_idx,
218                                                                          AVFormatContext *fmt_ctx, enum AVMediaType type)
219 {
220     int ret, stream_index;
221     AVStream *st;
222     AVCodecContext *dec_ctx = NULL;
223     AVCodec *dec = NULL;
224     AVDictionary *opts = NULL;
225
226     ret = av_find_best_stream(fmt_ctx, type, -1, -1, NULL, 0);
227     if (ret < 0) {
228         p_logger->debug_log(CSP_LOG_INFO, CSP_LOG_TYPE_SOUND_LOADER, "Could not find %s stream in input file '%s'\n",
229                 av_get_media_type_string(type), _filename.toLocal8Bit().constData());
230         return ret;
231     } else {
232         stream_index = ret;
233         st = fmt_ctx->streams[stream_index];
234
235         /* find decoder for the stream */
236         dec_ctx = st->codec;
237         dec = avcodec_find_decoder(dec_ctx->codec_id);
238         if (!dec) {
239             p_logger->debug_log(CSP_LOG_INFO, CSP_LOG_TYPE_SOUND_LOADER, "Failed to find %s codec\n",
240                     av_get_media_type_string(type));
241             return AVERROR(EINVAL);
242         }
243
244         /* Init the decoders, with or without reference counting */
245         av_dict_set(&opts, "refcounted_frames", "1", 0);
246         if ((ret = avcodec_open2(dec_ctx, dec, &opts)) < 0) {
247             p_logger->debug_log(CSP_LOG_INFO, CSP_LOG_TYPE_SOUND_LOADER, "Failed to open %s codec\n",
248                     av_get_media_type_string(type));
249             return ret;
250         }
251         *stream_idx = stream_index;
252     }
253
254     return 0;
255 }
256
257 int SOUND_LOADER::get_format_from_sample_fmt(const char **fmt,
258                                                                                          enum AVSampleFormat sample_fmt)
259 {
260     int i;
261     struct sample_fmt_entry {
262         enum AVSampleFormat sample_fmt; const char *fmt_be, *fmt_le;
263     } sample_fmt_entries[] = {
264         { AV_SAMPLE_FMT_U8,  "u8",    "u8"    },
265         { AV_SAMPLE_FMT_S16, "s16be", "s16le" },
266         { AV_SAMPLE_FMT_S32, "s32be", "s32le" },
267         { AV_SAMPLE_FMT_FLT, "f32be", "f32le" },
268         { AV_SAMPLE_FMT_DBL, "f64be", "f64le" },
269     };
270     *fmt = NULL;
271
272     for (i = 0; i < (int)FF_ARRAY_ELEMS(sample_fmt_entries); i++) {
273         struct sample_fmt_entry *entry = &sample_fmt_entries[i];
274         if (sample_fmt == entry->sample_fmt) {
275             *fmt = AV_NE(entry->fmt_be, entry->fmt_le);
276             return 0;
277         }
278     }
279
280     p_logger->debug_log(CSP_LOG_INFO, CSP_LOG_TYPE_SOUND_LOADER,
281             "sample format %s is not supported as output format\n",
282             av_get_sample_fmt_name(sample_fmt));
283     return -1;
284 }
285 #endif  
286
287 int SOUND_LOADER::do_decode_frames(void)
288 {
289         int got_frame = 1;
290         int decoded;
291         int ret;
292         if(sound_buffer != NULL) {
293                 free(sound_buffer);
294                 sound_buffer = NULL;
295         }
296 #if defined(USE_LIBAV)  
297         _data_size = 65536 * 2 * sizeof(int16_t);
298         sound_buffer = (int16_t *)malloc(_data_size);
299         if(sound_buffer == NULL) {
300                 return -1;
301         }
302         _dst_size = 0;
303         _dataptr = 0;
304         do {
305                 ret = av_read_frame(fmt_ctx, &pkt);
306                 if(ret < 0) break;
307                 decoded = decode_packet(&got_frame, 0);
308         } while((ret == 0) && (decoded >= 0));
309         return _dst_size;
310 #else
311         return 0;
312 #endif
313 }
314
315 const int16_t* SOUND_LOADER::get_sound_buffer(void)
316 {
317         return (const int16_t *)sound_buffer;
318 }
319
320 const int SOUND_LOADER::get_id(void)
321 {
322         return this_id;
323 }
324
325 void SOUND_LOADER::set_id(int id)
326 {
327         this_id = id;
328 }
329
330 const void *SOUND_LOADER::get_prev_sound_loader(void)
331 {
332         return (const void *)prev_loader;
333 }
334
335 const int SOUND_LOADER::get_dst_size(void)
336 {
337         return (const int)_dst_size;
338 }
339
340 void SOUND_LOADER::free_sound_buffer(int16_t *p)
341 {
342         if(p == NULL) {
343                 if(sound_buffer != NULL) free(sound_buffer);
344                 sound_buffer = NULL;
345                 this_id = -1;
346                 _dst_size = 0;
347                 _dataptr = 0;
348                 _data_size = 0;
349                 return;
350         }
351         if(p == sound_buffer) {
352                 free(sound_buffer);
353                 sound_buffer = NULL;
354                 this_id = -1;
355                 _dst_size = 0;
356                 _dataptr = 0;
357                 _data_size = 0;
358         }
359 }
360
361 void SOUND_LOADER::set_sound_rate(int rate)
362 {
363         sound_rate = rate;
364 }
365