4 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: Haejeong Kim <backto.kim@samsung.com>
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
12 * http://www.apache.org/licenses/LICENSE-2.0
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.
23 #include <string.h> /*memcmp*/
24 #include <stdlib.h> /*malloc*/
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"
33 /* Media specific definations */
34 #define NUM_AMR_NB_MODES 8
35 #define NUM_AMR_WB_MODES 9
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"
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
49 #define MMFILE_AMR_FRAME_DUR 20
50 #define AMR_NB_SAMPLES_PER_SEC 8000
51 #define AMR_WB_SAMPLES_PER_SEC 16000
53 #define AMR_MAX_READ_BUF_SZ 4096
55 #define AMR_GET_MODE(firstByte) (((firstByte) >> 3) & 0x0F)
58 typedef enum _mmfile_amr_format_types {
64 typedef enum _mmfile_amr_channel_type {
65 AMR_CHANNEL_TYPE_SINGLE,
66 AMR_CHANNEL_TYPE_MULTIPLE,
67 AMR_CHANNEL_TYPE_UNKNOWN
70 typedef struct _mmfile_amr_handle {
71 MMFileIOHandle *hFile;
74 unsigned int streamOffset;
76 unsigned int samplingRate;
77 unsigned int frameRate;
78 unsigned int numAudioChannels;
80 unsigned int numTracks;
82 eAmrFormatType amrFormat;
83 eAmrChannelType amrChannelType;
87 typedef struct _mmfile_amr_mode_config {
89 unsigned int frameSize;
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] = {
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},
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},
111 void _amr_init_handle(tMMFILE_AMR_HANDLE *pData)
115 pData->fileSize = 0L;
116 pData->streamOffset = 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;
126 int _parse_amr_header(tMMFILE_AMR_HANDLE *pData)
129 unsigned char header[MMFILE_AMR_MAX_HEADER_SIZE];
130 int ret = MMFILE_AMR_PARSER_SUCCESS;
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;
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]);
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;
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;
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;
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;
169 pData->amrFormat = AMR_FORMAT_UNKNOWN;
170 pData->amrChannelType = AMR_CHANNEL_TYPE_UNKNOWN;
171 ret = MMFILE_AMR_PARSER_FAIL;
178 int _parse_amr_stream(tMMFILE_AMR_HANDLE *pData)
181 unsigned char amrMode = 0;
182 int ret = MMFILE_AMR_PARSER_SUCCESS;
187 long long sum_bitrate = 0;
188 long long frames_bitrate = 0;
190 buf = mmfile_malloc(AMR_MAX_READ_BUF_SZ);
192 debug_error(DEBUG, "failed to memory allocaion.\n");
193 return MMFILE_AMR_PARSER_FAIL;
197 readed = mmfile_read(pData->hFile, buf, AMR_MAX_READ_BUF_SZ);
198 if (readed <= 0) break;
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;
205 frames_bitrate += (AmrModeConfigTable[pData->amrFormat][amrMode].bitRate == 0 ? 0 : 1);
211 } else if (pos > readed) {
212 mmfile_seek(pData->hFile, (pos - readed), MMFILE_SEEK_CUR);
220 pData->duration = pData->numFrames * MMFILE_AMR_FRAME_DUR;
221 pData->frameRate = 1000 / MMFILE_AMR_FRAME_DUR;
223 if (frames_bitrate) {
224 pData->bitRate = sum_bitrate / frames_bitrate;
231 int mmfile_amrparser_open(MMFileAMRHandle *handle, const char *filenamec)
233 tMMFILE_AMR_HANDLE *privateData = NULL;
236 if (NULL == filenamec || NULL == handle) {
237 debug_error(DEBUG, "file source is NULL\n");
238 return MMFILE_AMR_PARSER_FAIL;
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;
247 /* Initialize the members of handle */
248 _amr_init_handle(privateData);
250 ret = mmfile_open(&privateData->hFile, filenamec, MMFILE_RDONLY);
251 if (ret == MMFILE_UTIL_FAIL) {
252 debug_error(DEBUG, "error: mmfile_open\n");
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");
262 ret = _parse_amr_header(privateData);
263 if (ret == MMFILE_AMR_PARSER_FAIL) {
264 debug_error(DEBUG, "Invalid AMR header\n");
268 if (privateData->amrChannelType != AMR_CHANNEL_TYPE_SINGLE) {
269 debug_error(DEBUG, "Unsupported channel mode\n"); /*Need to study AMR_Format.txt, Pg:36*/
273 debug_msg(RELEASE, "AMR Format Type: %s\n", privateData->amrFormat == AMR_FORMAT_NB ? "AMR-NB" : "AMR-WB");
275 *handle = privateData;
277 return MMFILE_AMR_PARSER_SUCCESS;
281 mmfile_close(privateData->hFile);
282 mmfile_free(privateData);
285 return MMFILE_AMR_PARSER_FAIL;
290 int mmfile_amrparser_get_stream_info(MMFileAMRHandle handle, tMMFILE_AMR_STREAM_INFO *amrinfo)
292 tMMFILE_AMR_HANDLE *privateData = NULL;
295 if (NULL == handle || NULL == amrinfo) {
296 debug_error(DEBUG, "handle is NULL\n");
297 return MMFILE_AMR_PARSER_FAIL;
300 privateData = (tMMFILE_AMR_HANDLE *) handle;
302 mmfile_seek(privateData->hFile, privateData->streamOffset, MMFILE_SEEK_SET);
304 ret = _parse_amr_stream(privateData);
305 if (ret == MMFILE_AMR_PARSER_FAIL) {
306 debug_error(DEBUG, "Error in parsing the stream\n");
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;
317 if (privateData->amrFormat == AMR_FORMAT_NB) {
318 amrinfo->samplingRate = AMR_NB_SAMPLES_PER_SEC;
320 amrinfo->samplingRate = AMR_WB_SAMPLES_PER_SEC;
323 return MMFILE_AMR_PARSER_SUCCESS;
327 int mmfile_amrparser_close(MMFileAMRHandle handle)
329 tMMFILE_AMR_HANDLE *privateData = NULL;
331 if (NULL == handle) {
332 debug_error(DEBUG, "handle is NULL\n");
333 return MMFILE_AMR_PARSER_FAIL;
336 privateData = (tMMFILE_AMR_HANDLE *) handle;
338 mmfile_close(privateData->hFile);
340 return MMFILE_AMR_PARSER_SUCCESS;
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);
353 int mmfile_format_open_amr(MMFileFormatContext *formatContext)
355 MMFileAMRHandle handle = NULL;
356 int res = MMFILE_FORMAT_FAIL;
358 if (NULL == formatContext || NULL == formatContext->uriFileName) {
359 debug_error(DEBUG, "error: mmfile_format_open_amr\n");
360 return MMFILE_FORMAT_FAIL;
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;
368 formatContext->videoTotalTrackNum = 0;
369 formatContext->audioTotalTrackNum = 1;
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;
377 formatContext->privateFormatData = handle;
379 return MMFILE_FORMAT_SUCCESS;
383 int mmfile_format_read_stream_amr(MMFileFormatContext *formatContext)
385 MMFileAMRHandle handle = NULL;
386 tMMFILE_AMR_STREAM_INFO amrinfo = {0, };
387 MMFileFormatStream *audioStream = NULL;
389 int ret = MMFILE_FORMAT_FAIL;
391 if (NULL == formatContext) {
392 debug_error(DEBUG, "error: invalid params\n");
393 ret = MMFILE_FORMAT_FAIL;
397 handle = formatContext->privateFormatData;
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;
406 formatContext->duration = amrinfo.duration;
407 formatContext->videoStreamId = -1;
408 formatContext->videoTotalTrackNum = 0;
409 formatContext->audioTotalTrackNum = amrinfo.numTracks;
410 formatContext->nbStreams = 1;
412 audioStream = mmfile_malloc(sizeof(MMFileFormatStream));
413 if (NULL == audioStream) {
414 debug_error(DEBUG, "error: calloc_audiostream\n");
415 ret = MMFILE_FORMAT_FAIL;
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;
429 #ifdef __MMFILE_TEST_MODE__
430 mmfile_format_print_contents(formatContext);
433 return MMFILE_FORMAT_SUCCESS;
440 int mmfile_format_read_tag_amr(MMFileFormatContext *formatContext)
442 return MMFILE_FORMAT_SUCCESS;
447 int mmfile_format_read_frame_amr(MMFileFormatContext *formatContext, unsigned int timestamp, MMFileFormatFrame *frame)
449 debug_error(DEBUG, "error: mmfile_format_read_frame_amr, no handling\n");
451 return MMFILE_FORMAT_FAIL;
456 int mmfile_format_close_amr(MMFileFormatContext *formatContext)
458 MMFileAMRHandle handle = NULL;
459 int ret = MMFILE_FORMAT_FAIL;
461 if (NULL == formatContext) {
462 debug_error(DEBUG, "error: invalid params\n");
463 return MMFILE_FORMAT_FAIL;
466 handle = formatContext->privateFormatData;
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");
475 mmfile_free(formatContext->streams[MMFILE_AUDIO_STREAM]);
477 formatContext->ReadStream = NULL;
478 formatContext->ReadFrame = NULL;
479 formatContext->ReadTag = NULL;
480 formatContext->Close = NULL;
482 return MMFILE_FORMAT_SUCCESS;