Unify duplicated codes regarding getting file size
[platform/core/multimedia/libmm-fileinfo.git] / formats / ffmpeg / mm_file_format_amr.c
1 /*
2  * libmm-fileinfo
3  *
4  * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: Haejeong Kim <backto.kim@samsung.com>
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  */
21
22 #include <stdio.h>
23 #include <string.h>     /*memcmp*/
24 #include <stdlib.h>     /*malloc*/
25
26
27 #include "mm_file_debug.h"
28 #include "mm_file_utils.h"
29 #include "mm_file_format_private.h"
30 #include "mm_file_format_amr.h"
31
32
33 /* Media specific definations */
34 #define NUM_AMR_NB_MODES         8
35 #define NUM_AMR_WB_MODES         9
36
37 #define MMFILE_AMR_SINGLE_CH_HEADER_SIZE     6
38 #define MMFILE_AMR_SINGLE_CH_HEADER          "#!AMR\n"
39 #define MMFILE_AMR_WB_SINGLE_CH_HEADER_SIZE  9
40 #define MMFILE_AMR_WB_SINGLE_CH_HEADER       "#!AMR-WB\n"
41 #define MMFILE_AMR_MULTI_CH_HEADER_SIZE      12
42 #define MMFILE_AMR_MULTI_CH_HEADER           "#!AMR_MC1.0\n"
43 #define MMFILE_AMR_WB_MULTI_CH_HEADER_SIZE   15
44 #define MMFILE_AMR_WB_MULTI_CH_HEADER        "#!AMR-WB_MC1.0\n"
45
46 #define MMFILE_AMR_MAX_HEADER_SIZE  MMFILE_AMR_WB_MULTI_CH_HEADER_SIZE
47 #define MMFILE_AMR_MIN_HEADER_SIZE  MMFILE_AMR_SINGLE_CH_HEADER_SIZE
48
49 #define MMFILE_AMR_FRAME_DUR     20
50 #define AMR_NB_SAMPLES_PER_SEC   8000
51 #define AMR_WB_SAMPLES_PER_SEC   16000
52
53 #define AMR_MAX_READ_BUF_SZ     4096
54
55 #define AMR_GET_MODE(firstByte)  (((firstByte) >> 3) & 0x0F)
56
57
58 typedef enum _mmfile_amr_format_types {
59         AMR_FORMAT_NB,
60         AMR_FORMAT_WB,
61         AMR_FORMAT_UNKNOWN
62 } eAmrFormatType;
63
64 typedef enum _mmfile_amr_channel_type {
65         AMR_CHANNEL_TYPE_SINGLE,
66         AMR_CHANNEL_TYPE_MULTIPLE,
67         AMR_CHANNEL_TYPE_UNKNOWN
68 } eAmrChannelType;
69
70 typedef struct _mmfile_amr_handle {
71         MMFileIOHandle *hFile;
72         long long       duration;
73         long long       fileSize;
74         unsigned int    streamOffset;
75         unsigned int    bitRate;
76         unsigned int    samplingRate;
77         unsigned int    frameRate;
78         unsigned int    numAudioChannels;
79         long long       numFrames;
80         unsigned int    numTracks;
81         int             amrMode;
82         eAmrFormatType  amrFormat;
83         eAmrChannelType amrChannelType;
84 } tMMFILE_AMR_HANDLE;
85
86
87 typedef struct _mmfile_amr_mode_config {
88         unsigned int  bitRate;
89         unsigned int  frameSize;
90 } tAmrModeConfig;
91
92 /*RTP format only supported*/
93 /*mode vs bitRate-frameSize lookup table; [0]->AMR-NB  [1]->AMR-WB */
94 static const tAmrModeConfig AmrModeConfigTable[2][16] = {
95         {
96                 {4750, 13}, {5150, 14}, {5900, 16}, {6700, 18},
97                 {7400, 20}, {7950, 21}, {10200, 27}, {12200, 32},
98                 {0,     6}, {0,     1}, {0,     1}, {0,     1},
99                 {0,     1}, {0,     1}, {0,     1}, {0,     1},
100         },
101         {
102                 {6600, 18}, {8850, 24}, {12650, 33}, {14250, 37},
103                 {15850, 41}, {18250, 47}, {19850, 51}, {23050, 59},
104                 {23850, 61}, {0,     6}, {0,     6}, {0,     1},
105                 {0,     1}, {0,     1}, {0,     1}, {0,     1},
106         }
107 };
108
109 /* internal APIs */
110
111 void _amr_init_handle(tMMFILE_AMR_HANDLE *pData)
112 {
113         pData->hFile = NULL;
114         pData->duration = 0;
115         pData->fileSize = 0L;
116         pData->streamOffset = 0;
117         pData->bitRate = 0;
118         pData->samplingRate = 0;
119         pData->frameRate = 0;
120         pData->numAudioChannels = 1;
121         pData->numTracks = 1;
122         pData->numFrames = 0;
123         pData->amrChannelType = AMR_CHANNEL_TYPE_SINGLE;
124 }
125
126 int _parse_amr_header(tMMFILE_AMR_HANDLE *pData)
127 {
128
129         unsigned char header[MMFILE_AMR_MAX_HEADER_SIZE];
130         int ret = MMFILE_AMR_PARSER_SUCCESS;
131
132         ret = mmfile_read(pData->hFile, header, MMFILE_AMR_MAX_HEADER_SIZE);
133         if (ret != MMFILE_AMR_MAX_HEADER_SIZE) {
134                 return MMFILE_AMR_PARSER_FAIL;
135         }
136
137         debug_msg(RELEASE, "\nAMR HEADER: [%2x] [%2x] [%2x] [%2x] [%2x]\n   \
138                                 [%2x] [%2x] [%2x] [%2x] [%2x]\n   \
139                                 [%2x] [%2x] [%2x] [%2x] [%2x]\n",
140                                 header[0], header[1], header[2], header[3], header[4],
141                                 header[5], header[6], header[7], header[8], header[9],
142                                 header[10], header[11], header[12], header[13], header[14]);
143
144         if (!(memcmp(header, MMFILE_AMR_SINGLE_CH_HEADER, MMFILE_AMR_SINGLE_CH_HEADER_SIZE))) {
145                 pData->amrFormat = AMR_FORMAT_NB;
146                 pData->amrChannelType = AMR_CHANNEL_TYPE_SINGLE;
147                 pData->streamOffset = MMFILE_AMR_SINGLE_CH_HEADER_SIZE;
148         }
149
150         else if (!(memcmp(header, MMFILE_AMR_WB_SINGLE_CH_HEADER, MMFILE_AMR_WB_SINGLE_CH_HEADER_SIZE))) {
151                 pData->amrFormat = AMR_FORMAT_WB;
152                 pData->amrChannelType = AMR_CHANNEL_TYPE_SINGLE;
153                 pData->streamOffset = MMFILE_AMR_WB_SINGLE_CH_HEADER_SIZE;
154         }
155
156         else if (!(memcmp(header, MMFILE_AMR_MULTI_CH_HEADER, MMFILE_AMR_MULTI_CH_HEADER_SIZE))) {
157                 pData->amrFormat = AMR_FORMAT_NB;
158                 pData->amrChannelType = AMR_CHANNEL_TYPE_MULTIPLE;
159                 pData->streamOffset = MMFILE_AMR_MULTI_CH_HEADER_SIZE;
160         }
161
162         else if (!(memcmp(header, MMFILE_AMR_WB_MULTI_CH_HEADER, MMFILE_AMR_WB_MULTI_CH_HEADER_SIZE))) {
163                 pData->amrFormat = AMR_FORMAT_WB;
164                 pData->amrChannelType = AMR_CHANNEL_TYPE_MULTIPLE;
165                 pData->streamOffset = MMFILE_AMR_WB_MULTI_CH_HEADER_SIZE;
166         }
167
168         else {
169                 pData->amrFormat = AMR_FORMAT_UNKNOWN;
170                 pData->amrChannelType = AMR_CHANNEL_TYPE_UNKNOWN;
171                 ret = MMFILE_AMR_PARSER_FAIL;
172         }
173
174         return ret;
175 }
176
177
178 int _parse_amr_stream(tMMFILE_AMR_HANDLE *pData)
179 {
180         int frameLen = 0;
181         unsigned char amrMode = 0;
182         int ret = MMFILE_AMR_PARSER_SUCCESS;
183         unsigned char *p;
184         unsigned char *buf;
185         int readed;
186         int pos;
187         long long sum_bitrate = 0;
188         long long frames_bitrate = 0;
189
190         buf = mmfile_malloc(AMR_MAX_READ_BUF_SZ);
191         if (!buf) {
192                 debug_error(DEBUG, "failed to memory allocaion.\n");
193                 return MMFILE_AMR_PARSER_FAIL;
194         }
195
196         for (readed = 0;;) {
197                 readed = mmfile_read(pData->hFile, buf, AMR_MAX_READ_BUF_SZ);
198                 if (readed <= 0) break;
199
200                 for (p = buf, pos = 0;;) {
201                         amrMode = AMR_GET_MODE((*(char *)p));
202                         frameLen = AmrModeConfigTable[pData->amrFormat][amrMode].frameSize;
203                         sum_bitrate += AmrModeConfigTable[pData->amrFormat][amrMode].bitRate;
204                         pData->numFrames++;
205                         frames_bitrate += (AmrModeConfigTable[pData->amrFormat][amrMode].bitRate == 0 ? 0 : 1);
206
207                         p += frameLen;
208                         pos += frameLen;
209                         if (pos == readed) {
210                                 break;
211                         } else  if (pos > readed) {
212                                 mmfile_seek(pData->hFile, (pos - readed), MMFILE_SEEK_CUR);
213                                 break;
214                         }
215                 }
216         }
217
218         mmfile_free(buf);
219
220         pData->duration = pData->numFrames * MMFILE_AMR_FRAME_DUR;
221         pData->frameRate = 1000 / MMFILE_AMR_FRAME_DUR;
222
223         if (frames_bitrate) {
224                 pData->bitRate = sum_bitrate / frames_bitrate;
225         }
226
227         return ret;
228 }
229
230
231 int mmfile_amrparser_open(MMFileAMRHandle *handle, const char *filenamec)
232 {
233         tMMFILE_AMR_HANDLE *privateData = NULL;
234         int ret = 0;
235
236         if (NULL == filenamec || NULL == handle) {
237                 debug_error(DEBUG, "file source is NULL\n");
238                 return MMFILE_AMR_PARSER_FAIL;
239         }
240
241         privateData = mmfile_malloc(sizeof(tMMFILE_AMR_HANDLE));
242         if (NULL == privateData) {
243                 debug_error(DEBUG, "file source is NULL\n");
244                 return MMFILE_AMR_PARSER_FAIL;
245         }
246
247         /* Initialize the members of handle */
248         _amr_init_handle(privateData);
249
250         ret = mmfile_open(&privateData->hFile, filenamec, MMFILE_RDONLY);
251         if (ret == MMFILE_UTIL_FAIL) {
252                 debug_error(DEBUG, "error: mmfile_open\n");
253                 goto exception;
254         }
255
256         privateData->fileSize = mmfile_get_size(privateData->hFile);
257         if (privateData->fileSize < MMFILE_AMR_MIN_HEADER_SIZE) {
258                 debug_error(DEBUG, "Too small file to parse!!\n");
259                 goto exception;
260         }
261
262         ret = _parse_amr_header(privateData);
263         if (ret == MMFILE_AMR_PARSER_FAIL) {
264                 debug_error(DEBUG, "Invalid AMR header\n");
265                 goto exception;
266         }
267
268         if (privateData->amrChannelType != AMR_CHANNEL_TYPE_SINGLE) {
269                 debug_error(DEBUG, "Unsupported channel mode\n"); /*Need to study AMR_Format.txt, Pg:36*/
270                 goto exception;
271         }
272
273         debug_msg(RELEASE, "AMR Format Type: %s\n", privateData->amrFormat == AMR_FORMAT_NB ? "AMR-NB" : "AMR-WB");
274
275         *handle = privateData;
276
277         return MMFILE_AMR_PARSER_SUCCESS;
278
279 exception:
280         if (privateData) {
281                 mmfile_close(privateData->hFile);
282                 mmfile_free(privateData);
283                 *handle = NULL;
284         }
285         return MMFILE_AMR_PARSER_FAIL;
286
287 }
288
289
290 int mmfile_amrparser_get_stream_info(MMFileAMRHandle handle, tMMFILE_AMR_STREAM_INFO *amrinfo)
291 {
292         tMMFILE_AMR_HANDLE *privateData = NULL;
293         int ret;
294
295         if (NULL == handle || NULL == amrinfo) {
296                 debug_error(DEBUG, "handle is NULL\n");
297                 return MMFILE_AMR_PARSER_FAIL;
298         }
299
300         privateData = (tMMFILE_AMR_HANDLE *) handle;
301
302         mmfile_seek(privateData->hFile, privateData->streamOffset, MMFILE_SEEK_SET);
303
304         ret = _parse_amr_stream(privateData);
305         if (ret == MMFILE_AMR_PARSER_FAIL) {
306                 debug_error(DEBUG, "Error in parsing the stream\n");
307                 return ret;
308         }
309
310         amrinfo->duration = privateData->duration;
311         amrinfo->fileSize = privateData->fileSize;
312         amrinfo->bitRate = privateData->bitRate;
313         amrinfo->frameRate = privateData->frameRate;
314         amrinfo->numAudioChannels = 1;
315         amrinfo->numTracks = 1;
316
317         if (privateData->amrFormat == AMR_FORMAT_NB) {
318                 amrinfo->samplingRate = AMR_NB_SAMPLES_PER_SEC;
319         } else {
320                 amrinfo->samplingRate = AMR_WB_SAMPLES_PER_SEC;
321         }
322
323         return MMFILE_AMR_PARSER_SUCCESS;
324 }
325
326
327 int mmfile_amrparser_close(MMFileAMRHandle handle)
328 {
329         tMMFILE_AMR_HANDLE *privateData = NULL;
330
331         if (NULL == handle) {
332                 debug_error(DEBUG, "handle is NULL\n");
333                 return MMFILE_AMR_PARSER_FAIL;
334         }
335
336         privateData = (tMMFILE_AMR_HANDLE *) handle;
337
338         mmfile_close(privateData->hFile);
339
340         return MMFILE_AMR_PARSER_SUCCESS;
341 }
342
343
344
345 /* mm plugin interface */
346 int mmfile_format_read_stream_amr(MMFileFormatContext *formatContext);
347 int mmfile_format_read_frame_amr(MMFileFormatContext *formatContext, unsigned int timestamp, MMFileFormatFrame *frame);
348 int mmfile_format_read_tag_amr(MMFileFormatContext *formatContext);
349 int mmfile_format_close_amr(MMFileFormatContext *formatContext);
350
351
352 EXPORT_API
353 int mmfile_format_open_amr(MMFileFormatContext *formatContext)
354 {
355         MMFileAMRHandle handle = NULL;
356         int res = MMFILE_FORMAT_FAIL;
357
358         if (NULL == formatContext || NULL == formatContext->uriFileName) {
359                 debug_error(DEBUG, "error: mmfile_format_open_amr\n");
360                 return MMFILE_FORMAT_FAIL;
361         }
362
363         formatContext->ReadStream   = mmfile_format_read_stream_amr;
364         formatContext->ReadFrame    = mmfile_format_read_frame_amr;
365         formatContext->ReadTag      = mmfile_format_read_tag_amr;
366         formatContext->Close        = mmfile_format_close_amr;
367
368         formatContext->videoTotalTrackNum = 0;
369         formatContext->audioTotalTrackNum = 1;
370
371         res = mmfile_amrparser_open(&handle, formatContext->uriFileName);
372         if (MMFILE_AMR_PARSER_FAIL == res) {
373                 debug_error(DEBUG, "mmfile_amrparser_open\n");
374                 return MMFILE_FORMAT_FAIL;
375         }
376
377         formatContext->privateFormatData = handle;
378
379         return MMFILE_FORMAT_SUCCESS;
380 }
381
382 EXPORT_API
383 int mmfile_format_read_stream_amr(MMFileFormatContext *formatContext)
384 {
385         MMFileAMRHandle     handle = NULL;
386         tMMFILE_AMR_STREAM_INFO  amrinfo = {0, };
387         MMFileFormatStream  *audioStream = NULL;
388
389         int ret = MMFILE_FORMAT_FAIL;
390
391         if (NULL == formatContext) {
392                 debug_error(DEBUG, "error: invalid params\n");
393                 ret = MMFILE_FORMAT_FAIL;
394                 goto exception;
395         }
396
397         handle = formatContext->privateFormatData;
398
399         ret = mmfile_amrparser_get_stream_info(handle, &amrinfo);
400         if (MMFILE_FORMAT_SUCCESS != ret) {
401                 debug_error(DEBUG, "error: mmfile_amrparser_get_stream_info\n");
402                 ret = MMFILE_FORMAT_FAIL;
403                 goto exception;
404         }
405
406         formatContext->duration = amrinfo.duration;
407         formatContext->videoStreamId = -1;
408         formatContext->videoTotalTrackNum = 0;
409         formatContext->audioTotalTrackNum = amrinfo.numTracks;
410         formatContext->nbStreams = 1;
411
412         audioStream = mmfile_malloc(sizeof(MMFileFormatStream));
413         if (NULL == audioStream) {
414                 debug_error(DEBUG, "error: calloc_audiostream\n");
415                 ret = MMFILE_FORMAT_FAIL;
416                 goto exception;
417         }
418
419         audioStream->streamType = MMFILE_AUDIO_STREAM;
420         audioStream->codecId = MM_AUDIO_CODEC_AMR;
421         audioStream->bitRate = amrinfo.bitRate;
422         audioStream->framePerSec = amrinfo.frameRate;
423         audioStream->width = 0;
424         audioStream->height = 0;
425         audioStream->nbChannel = amrinfo.numAudioChannels;
426         audioStream->samplePerSec = amrinfo.samplingRate;
427         formatContext->streams[MMFILE_AUDIO_STREAM] = audioStream;
428
429 #ifdef  __MMFILE_TEST_MODE__
430         mmfile_format_print_contents(formatContext);
431 #endif
432
433         return MMFILE_FORMAT_SUCCESS;
434
435 exception:
436         return ret;
437 }
438
439 EXPORT_API
440 int mmfile_format_read_tag_amr(MMFileFormatContext *formatContext)
441 {
442         return MMFILE_FORMAT_SUCCESS;
443 }
444
445
446 EXPORT_API
447 int mmfile_format_read_frame_amr(MMFileFormatContext *formatContext, unsigned int timestamp, MMFileFormatFrame *frame)
448 {
449         debug_error(DEBUG, "error: mmfile_format_read_frame_amr, no handling\n");
450
451         return MMFILE_FORMAT_FAIL;
452 }
453
454
455 EXPORT_API
456 int mmfile_format_close_amr(MMFileFormatContext *formatContext)
457 {
458         MMFileAMRHandle  handle = NULL;
459         int ret = MMFILE_FORMAT_FAIL;
460
461         if (NULL == formatContext) {
462                 debug_error(DEBUG, "error: invalid params\n");
463                 return MMFILE_FORMAT_FAIL;
464         }
465
466         handle = formatContext->privateFormatData;
467
468         if (NULL != handle) {
469                 ret = mmfile_amrparser_close(handle);
470                 if (ret == MMFILE_AMR_PARSER_FAIL) {
471                         debug_error(DEBUG, "error: mmfile_format_close_amr\n");
472                 }
473         }
474
475         mmfile_free(formatContext->streams[MMFILE_AUDIO_STREAM]);
476
477         formatContext->ReadStream   = NULL;
478         formatContext->ReadFrame    = NULL;
479         formatContext->ReadTag      = NULL;
480         formatContext->Close        = NULL;
481
482         return MMFILE_FORMAT_SUCCESS;
483 }
484
485