bunch of small fixes, add msg.txt to about prefs
[goodguy/history.git] / cinelerra-5.0 / quicktime / qdm2.c
1 #include "funcprotos.h"
2 #include "quicktime.h"
3 #include "qtffmpeg.h"
4
5 #include <stdint.h>
6 #include <string.h>
7
8 extern int ffmpeg_initialized;
9 extern pthread_mutex_t ffmpeg_lock;
10
11
12 typedef struct
13 {
14         int decoder_initialized;
15         AVCodec *decoder;
16         AVCodecContext *decoder_context;
17         
18 // Number of frames
19         int frame_size;
20         int max_frame_bytes;
21 // Input samples interleaved
22         int16_t *input_buffer;
23 // Number of samples allocated
24         int input_allocated;
25 // Last sample decoded in the input buffer + 1
26         int64_t input_end;
27 // Total samples in input buffer
28         int input_size;
29 // Current write offset in input buffer
30         int input_ptr;
31         
32         unsigned char *compressed_buffer;
33         int compressed_size;
34         int compressed_allocated;
35         int16_t *temp_buffer;
36
37 // Next chunk to decode sequentially
38         int64_t current_chunk;
39 } quicktime_qdm2_codec_t;
40
41 #define MAX(x, y) ((x) > (y) ? (x) : (y))
42 // Default number of samples to allocate in work buffer
43 #define OUTPUT_ALLOCATION 0x100000
44
45
46
47
48
49 static void delete_codec(quicktime_audio_map_t *atrack)
50 {
51         quicktime_qdm2_codec_t *codec = 
52                 ((quicktime_codec_t*)atrack->codec)->priv;
53
54         if(codec->decoder_initialized)
55         {
56                 avcodec_close(codec->decoder_context);
57                 free(codec->decoder_context);
58         }
59
60         if(codec->input_buffer) free(codec->input_buffer);
61         if(codec->compressed_buffer) free(codec->compressed_buffer);
62         if(codec->temp_buffer) free(codec->temp_buffer);
63
64         free(codec);
65 }
66
67 void allocate_compressed(quicktime_qdm2_codec_t *codec, int size)
68 {
69         if(size > codec->compressed_allocated)
70         {
71                 codec->compressed_buffer = realloc(codec->compressed_buffer, size);
72                 codec->compressed_allocated = size;
73         }
74 }
75
76 static int decode(quicktime_t *file, 
77                                         int16_t *output_i, 
78                                         float *output_f, 
79                                         long samples, 
80                                         int track, 
81                                         int channel)
82 {
83         quicktime_audio_map_t *track_map = &(file->atracks[track]);
84         quicktime_trak_t *trak = track_map->track;
85         quicktime_qdm2_codec_t *codec = ((quicktime_codec_t*)track_map->codec)->priv;
86         quicktime_stsd_table_t *stsd_table = &trak->mdia.minf.stbl.stsd.table[0];
87         int64_t current_position = track_map->current_position;
88         int64_t end_position = current_position + samples;
89         quicktime_frma_t *frma = &stsd_table->frma;
90         int channels = track_map->channels;
91         int i, j;
92         int debug = 0;
93         int64_t chunk_sample;
94         
95
96
97 // Initialize decoder
98         if(!codec->decoder_initialized)
99         {
100                 pthread_mutex_lock(&ffmpeg_lock);
101                 if(!ffmpeg_initialized)
102                 {
103                         ffmpeg_initialized = 1;
104                         av_register_all();
105                 }
106
107                 codec->decoder = avcodec_find_decoder(CODEC_ID_QDM2);
108                 if(!codec->decoder)
109                 {
110                         printf("qdm2.c: decode: no ffmpeg decoder found.\n");
111                         return 1;
112                 }
113
114 // allocate the codec and fill in header
115                 AVCodecContext *context = avcodec_alloc_context3(codec->decoder);
116                 codec->decoder_context = context;
117                 codec->decoder_context->sample_rate = trak->mdia.minf.stbl.stsd.table[0].sample_rate;
118                 codec->decoder_context->channels = track_map->channels;
119
120                 if(frma->data && frma->data_size)
121                 {
122                         context->extradata = (unsigned char *)frma->data;
123                         context->extradata_size = frma->data_size;
124                 }
125
126                 if(file->cpus > 1)
127                 {
128 //                      avcodec_thread_init(context, file->cpus);
129                         context->thread_count = file->cpus;
130                 }
131         
132                 if(avcodec_open2(context, codec->decoder, 0) < 0)
133                 {
134                         printf("qdm2.c: decode: avcodec_open failed.\n");
135                         return 1;
136                 }
137                 pthread_mutex_unlock(&ffmpeg_lock);
138                 
139                 codec->input_buffer = calloc(sizeof(int16_t),
140                         track_map->channels * OUTPUT_ALLOCATION);
141                 codec->input_allocated = OUTPUT_ALLOCATION;
142
143                         
144                 codec->decoder_initialized = 1;
145         }
146
147
148         if(samples > OUTPUT_ALLOCATION)
149         {
150                 printf("qdm2: decode: can't decode more than 0x%x samples at a time.\n",
151                         OUTPUT_ALLOCATION);
152                 return 1;
153         }
154
155         if(debug)
156         {
157                 printf("qdm2 decode: current_position=%jd end_position=%jd input_size=%d input_end=%jd\n",
158                         current_position, end_position, codec->input_size, codec->input_end);
159         }
160
161 // printf("qdm2 decode: current_position=%lld end_position=%lld chunk_sample=%lld chunk=%lld\n", 
162 // current_position, 
163 // end_position,
164 // chunk_sample,
165 // chunk);
166
167
168         if(current_position < codec->input_end - codec->input_size ||
169                 current_position > codec->input_end)
170         {
171 // Desired start point is outside existing range.  Reposition buffer pointer
172 // to start time of nearest chunk and start over.
173                 quicktime_chunk_of_sample(&chunk_sample, 
174                         &codec->current_chunk, 
175                         trak, 
176                         current_position);
177                 codec->input_size = 0;
178                 codec->input_ptr = 0;
179                 codec->input_end = chunk_sample;
180         }
181
182 // Decode complete chunks until samples is reached
183         int total_chunks = trak->mdia.minf.stbl.stco.total_entries;
184         while(codec->input_end < end_position)
185         {
186                 int64_t offset = quicktime_chunk_to_offset(file, 
187                         trak, 
188                         codec->current_chunk);
189                 int64_t max_offset = quicktime_chunk_to_offset(file, 
190                         trak, 
191                         codec->current_chunk + 1);
192                 quicktime_set_position(file, offset);
193                 allocate_compressed(codec, 3);
194
195                 if(debug)
196                 {
197                         printf("qdm2 decode: input_end=%jd chunk=%jd offset=0x%jx\n", 
198                                 codec->input_end, codec->current_chunk, offset);
199                 }
200
201 // Read fragments of chunk
202                 while(1)
203                 {
204 // Hit next chunk of audio
205                         if(max_offset > offset && quicktime_position(file) >= max_offset) break;
206                         if(!quicktime_read_data(file, 
207                                 (char*)codec->compressed_buffer + codec->compressed_size, 
208                                 3))
209                                 break;
210                         if(codec->compressed_buffer[codec->compressed_size] != 0x82)
211                         {
212 //                              printf("qdm2: decode: position=0x%llx\n", quicktime_position(file));
213                                 break;
214                         }
215                         int fragment_size = 3 + ((codec->compressed_buffer[codec->compressed_size + 1] << 8) |
216                                 codec->compressed_buffer[codec->compressed_size + 2]);
217 // Sanity check
218                         if(fragment_size > OUTPUT_ALLOCATION) break;
219 // Expand compressed buffer
220                         allocate_compressed(codec, 
221                                 codec->compressed_size + fragment_size + 1024);
222                         if(!quicktime_read_data(file, 
223                                 (char*)codec->compressed_buffer + codec->compressed_size + 3, 
224                                 fragment_size - 3))
225                                 break;
226
227                         codec->compressed_size += fragment_size;
228
229                         AVPacket avpkt;
230                         av_init_packet(&avpkt);
231                         avpkt.data = codec->compressed_buffer;
232                         avpkt.size = codec->compressed_size;
233
234                         int count = 0;
235 // Repeat this sequence until ffmpeg stops outputting samples
236                         while(1)
237                         {
238                                 if(!codec->temp_buffer)
239                                         codec->temp_buffer = calloc(sizeof(int16_t), OUTPUT_ALLOCATION);
240                                 int bytes_decoded = OUTPUT_ALLOCATION * sizeof(int16_t);
241                                 int result = quicktime_decode_audio3(codec->decoder_context, 
242                                         codec->temp_buffer, &bytes_decoded, &avpkt);
243
244 // Shift compressed buffer
245                                 if(result > 0)
246                                 {
247                                         avpkt.size -= result;
248                                         avpkt.data += result;
249                                         count += result;
250                                 }
251
252 //printf("avcodec_decode_audio result=%d bytes_decoded=%d fragment_size=%d codec->compressed_size=%d\n", 
253 //result, bytes_decoded, fragment_size, codec->compressed_size);
254 /*
255  * static FILE *test = 0;
256  * if(!test) test = fopen("/tmp/debug", "w");
257  * fwrite(codec->temp_buffer, 1, bytes_decoded, test);
258  * fflush(test);
259  */
260                                 for(i = 0; i < bytes_decoded / channels / sizeof(int16_t); i++)
261                                 {
262                                         for(j = 0; j < channels; j++)
263                                                 codec->input_buffer[codec->input_ptr * channels + j] =
264                                                         codec->temp_buffer[i * channels + j];
265                                         codec->input_ptr++;
266                                         if(codec->input_ptr >= codec->input_allocated)
267                                                 codec->input_ptr = 0;
268                                 }
269                                 codec->input_end += bytes_decoded / channels / sizeof(int16_t);
270                                 codec->input_size += bytes_decoded / channels / sizeof(int16_t);
271
272                                 if(bytes_decoded <= 0) break;
273                         }
274
275                         if( count > 0 ) {
276                                 memcpy(codec->compressed_buffer,
277                                         codec->compressed_buffer + count,
278                                         codec->compressed_size -= count);
279                         }
280                 }
281
282                 codec->current_chunk++;
283                 if(codec->current_chunk >= total_chunks) break;
284         }
285
286 // Transfer from buffer to output
287         int input_ptr = codec->input_ptr - (codec->input_end - current_position);
288         if(input_ptr < 0) input_ptr += codec->input_allocated;
289         if(output_i)
290         {
291                 for(i = 0; i < samples; i++)
292                 {
293                         output_i[i] = codec->input_buffer[input_ptr * channels + channel];
294                         input_ptr++;
295                         if(input_ptr >= codec->input_allocated) input_ptr = 0;
296                 }
297         }
298         else
299         if(output_f)
300         {
301                 for(i = 0; i < samples; i++)
302                 {
303                         output_f[i] = (float)codec->input_buffer[input_ptr * channels + channel] / 32768.0;
304                         input_ptr++;
305                         if(input_ptr >= codec->input_allocated) input_ptr = 0;
306                 }
307         }
308         return 0;
309 }
310
311
312
313
314
315 void quicktime_init_codec_qdm2(quicktime_audio_map_t *atrack)
316 {
317         quicktime_codec_t *codec_base = (quicktime_codec_t*)atrack->codec;
318         codec_base->priv = calloc(1, sizeof(quicktime_qdm2_codec_t));
319         codec_base->delete_acodec = delete_codec;
320         codec_base->decode_audio = decode;
321         codec_base->encode_audio = 0;
322         codec_base->set_parameter = 0;
323         codec_base->flush = 0;
324         codec_base->fourcc = "QDM2";
325         codec_base->title = "QDesign Music 2";
326         codec_base->desc = "QDesign Music 2";
327 }
328
329
330
331