r571: fix missing eos
[cinelerra_cv/mob.git] / quicktime / wma.c
blob1cf03c07b8bf76ad6e253bb9bd50b61c4600e983
1 #include <ffmpeg/avcodec.h>
2 #include "funcprotos.h"
3 #include "quicktime.h"
4 #include "wma.h"
6 /* McRowesoft media player audio */
7 /* WMA derivatives */
9 typedef struct
11 // Sample output
12 char *work_buffer;
13 // Number of first sample in output relative to file
14 int64_t output_position;
15 // Number of samples in output buffer
16 long output_size;
17 // Number of samples allocated in output buffer
18 long output_allocated;
19 char *packet_buffer;
20 int packet_allocated;
21 // Current reading position in file
22 int64_t chunk;
26 int ffmpeg_id;
27 AVCodec *decoder;
28 AVCodecContext *decoder_context;
29 int decode_initialized;
30 } quicktime_wma_codec_t;
34 // Default number of samples to allocate in work buffer
35 #define OUTPUT_ALLOCATION 0x100000
37 static int delete_codec(quicktime_audio_map_t *atrack)
39 quicktime_wma_codec_t *codec = ((quicktime_codec_t*)atrack->codec)->priv;
41 if(codec->decode_initialized)
43 pthread_mutex_lock(&ffmpeg_lock);
44 avcodec_close(codec->decoder_context);
45 free(codec->decoder_context);
46 pthread_mutex_unlock(&ffmpeg_lock);
47 codec->decode_initialized = 0;
50 if(codec->work_buffer)
51 free(codec->work_buffer);
52 if(codec->packet_buffer)
53 free(codec->packet_buffer);
54 free(codec);
59 static int init_decode(quicktime_audio_map_t *track_map,
60 quicktime_wma_codec_t *codec)
62 if(!codec->decode_initialized)
64 quicktime_trak_t *trak = track_map->track;
65 pthread_mutex_lock(&ffmpeg_lock);
66 if(!ffmpeg_initialized)
68 ffmpeg_initialized = 1;
69 avcodec_init();
70 avcodec_register_all();
73 codec->decoder = avcodec_find_decoder(codec->ffmpeg_id);
74 if(!codec->decoder)
76 printf("init_decode: avcodec_find_decoder returned NULL.\n");
77 return 1;
79 codec->decoder_context = avcodec_alloc_context();
80 codec->decoder_context->sample_rate = trak->mdia.minf.stbl.stsd.table[0].sample_rate;
81 codec->decoder_context->channels = track_map->channels;
82 if(avcodec_open(codec->decoder_context, codec->decoder) < 0)
84 printf("init_decode: avcodec_open failed.\n");
85 return 1;
87 pthread_mutex_unlock(&ffmpeg_lock);
89 codec->work_buffer = malloc(2 * track_map->channels * OUTPUT_ALLOCATION);
90 codec->output_allocated = OUTPUT_ALLOCATION;
92 return 0;
95 static int decode(quicktime_t *file,
96 int16_t *output_i,
97 float *output_f,
98 long samples,
99 int track,
100 int channel)
102 quicktime_audio_map_t *track_map = &(file->atracks[track]);
103 quicktime_wma_codec_t *codec = ((quicktime_codec_t*)track_map->codec)->priv;
104 quicktime_trak_t *trak = track_map->track;
105 long current_position = track_map->current_position;
106 long end_position = current_position + samples;
107 int try = 0;
108 int result = 0;
109 int i, j;
110 int sample_size = 2 * track_map->channels;
112 if(output_i) bzero(output_i, sizeof(int16_t) * samples);
113 if(output_f) bzero(output_f, sizeof(float) * samples);
115 if(samples > OUTPUT_ALLOCATION)
116 printf("decode: can't read more than %d samples at a time.\n", OUTPUT_ALLOCATION);
118 result = init_decode(track_map, codec);
119 if(result) return 1;
121 // Seeked outside output buffer's range or not initialized: restart
122 if(current_position < codec->output_position ||
123 current_position > codec->output_position + codec->output_size ||
124 !codec->decode_initialized)
126 quicktime_chunk_of_sample(&codec->output_position,
127 &codec->chunk,
128 trak,
129 current_position);
131 //printf("decode 1 %lld %d\n", codec->output_position, codec->chunk);
132 // We know the first mp3 packet in the chunk has a pcm_offset from the encoding.
133 codec->output_size = 0;
134 codec->decode_initialized = 1;
137 // Decode chunks until output buffer covers requested range
138 while(codec->output_position + codec->output_size <
139 current_position + samples &&
140 try < 256)
142 // Load chunk into work buffer
143 int64_t chunk_offset = 0;
144 int chunk_samples = quicktime_chunk_samples(trak, codec->chunk);
145 int chunk_size = quicktime_chunk_bytes(file,
146 &chunk_offset,
147 codec->chunk,
148 trak);
149 // Getting invalid numbers for this
150 // int max_samples = chunk_samples * 2;
151 int max_samples = 32768;
152 int max_bytes = max_samples * sample_size;
153 int bytes_decoded = 0;
154 printf("decode 2 %x %llx %llx\n", chunk_size, chunk_offset, chunk_offset + chunk_size);
156 // Allocate packet buffer
157 if(codec->packet_allocated < chunk_size &&
158 codec->packet_buffer)
160 free(codec->packet_buffer);
161 codec->packet_buffer = 0;
164 if(!codec->packet_buffer)
166 codec->packet_buffer = calloc(1, chunk_size);
167 codec->packet_allocated = chunk_size;
170 // Allocate work buffer
171 if(max_bytes + codec->output_size * sample_size > codec->output_allocated * sample_size)
173 char *new_output = calloc(1, max_bytes + codec->output_size * sample_size);
174 if(codec->work_buffer)
176 memcpy(new_output, codec->work_buffer, codec->output_size * sample_size);
177 free(codec->work_buffer);
179 codec->work_buffer = new_output;
180 codec->output_allocated = max_bytes + codec->output_size * sample_size;
183 quicktime_set_position(file, chunk_offset);
184 result = !quicktime_read_data(file, codec->packet_buffer, chunk_size);
185 if(result) break;
187 // Decode chunk into work buffer.
188 pthread_mutex_lock(&ffmpeg_lock);
189 result = avcodec_decode_audio(codec->decoder_context,
190 (int16_t*)(codec->work_buffer + codec->output_size * sample_size),
191 &bytes_decoded,
192 codec->packet_buffer,
193 chunk_size);
194 pthread_mutex_unlock(&ffmpeg_lock);
195 if(bytes_decoded <= 0)
197 try++;
199 else
201 if(codec->output_size * sample_size + bytes_decoded > codec->output_allocated * sample_size)
202 printf("decode: FYI: bytes_decoded=%d is greater than output_allocated=%d\n",
203 codec->output_size * sample_size + bytes_decoded,
204 codec->output_allocated);
205 codec->output_size += bytes_decoded / sample_size;
206 try = 0;
208 codec->chunk++;
211 //printf("decode 15 %d %lld %d\n", try, codec->output_position, codec->output_size);
212 // Transfer to output
213 if(output_i)
215 int16_t *pcm_ptr = (int16_t*)codec->work_buffer +
216 (current_position - codec->output_position) * track_map->channels +
217 channel;
218 for(i = current_position - codec->output_position, j = 0;
219 j < samples && i < codec->output_size;
220 j++, i++)
222 output_i[j] = *pcm_ptr;
223 pcm_ptr += track_map->channels;
226 else
227 if(output_f)
229 int16_t *pcm_ptr = (int16_t*)codec->work_buffer +
230 (current_position - codec->output_position) * track_map->channels +
231 channel;
232 for(i = current_position - codec->output_position, j = 0;
233 j < samples && i < codec->output_size;
234 j++, i++)
236 output_i[j] = (float)*pcm_ptr / (float)32767;
237 pcm_ptr += track_map->channels;
241 // Delete excess output
242 if(codec->output_size > OUTPUT_ALLOCATION)
244 int sample_diff = codec->output_size - OUTPUT_ALLOCATION;
245 int byte_diff = sample_diff * sample_size;
246 memcpy(codec->work_buffer,
247 codec->work_buffer + byte_diff,
248 OUTPUT_ALLOCATION * sample_size);
249 codec->output_size -= sample_diff;
250 codec->output_position += sample_diff;
253 return 0;
262 static void init_codec_common(quicktime_audio_map_t *atrack)
264 quicktime_wma_codec_t *codec;
265 quicktime_codec_t *codec_base = (quicktime_codec_t*)atrack->codec;
267 /* Init public items */
268 codec_base->delete_acodec = delete_codec;
269 codec_base->decode_audio = decode;
272 /* Init private items */
273 codec = codec_base->priv = calloc(1, sizeof(quicktime_wma_codec_t));
277 void quicktime_init_codec_wmav1(quicktime_audio_map_t *atrack)
279 quicktime_codec_t *codec_base = (quicktime_codec_t*)atrack->codec;
280 quicktime_wma_codec_t *codec;
281 init_codec_common(atrack);
283 codec = codec_base->priv;
284 codec_base->fourcc = QUICKTIME_WMA;
285 codec_base->title = "Win Media Audio 1";
286 codec_base->desc = "Win Media Audio 1";
287 codec_base->wav_id = 0x160;
288 codec->ffmpeg_id = CODEC_ID_WMAV1;
292 void quicktime_init_codec_wmav2(quicktime_audio_map_t *atrack)
294 quicktime_codec_t *codec_base = (quicktime_codec_t*)atrack->codec;
295 quicktime_wma_codec_t *codec;
296 init_codec_common(atrack);
298 codec = codec_base->priv;
299 codec_base->fourcc = QUICKTIME_WMA;
300 codec_base->title = "Win Media Audio 2";
301 codec_base->desc = "Win Media Audio 2";
302 codec_base->wav_id = 0x161;
303 codec->ffmpeg_id = CODEC_ID_WMAV2;