1/* ------------------------------------------------------------------
2 * Copyright (C) 1998-2009 PacketVideo
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
13 * express or implied.
14 * See the License for the specific language governing permissions
15 * and limitations under the License.
16 * -------------------------------------------------------------------
17 */
18
19#include "ti_video_config_parser.h"
20#include "ti_m4v_config_parser.h"
21#include "oscl_mem.h"
22
23#include "oscl_dll.h"
24
25#define GetUnalignedWord( pb, w ) \
26            (w) = ((uint16) *(pb + 1) << 8) + *pb;
27
28#define GetUnalignedDword( pb, dw ) \
29            (dw) = ((uint32) *(pb + 3) << 24) + \
30                   ((uint32) *(pb + 2) << 16) + \
31                   ((uint16) *(pb + 1) << 8) + *pb;
32
33#define GetUnalignedWordEx( pb, w )     GetUnalignedWord( pb, w ); (pb) += sizeof(uint16);
34#define GetUnalignedDwordEx( pb, dw )   GetUnalignedDword( pb, dw ); (pb) += sizeof(uint32);
35#define GetUnalignedQwordEx( pb, qw )   GetUnalignedQword( pb, qw ); (pb) += sizeof(uint64);
36
37#define LoadBYTE( b, p )    b = *(uint8 *)p;  p += sizeof( uint8 )
38
39#define LoadWORD( w, p )    GetUnalignedWordEx( p, w )
40#define LoadDWORD( dw, p )  GetUnalignedDwordEx( p, dw )
41#define LoadQWORD( qw, p )  GetUnalignedQwordEx( p, qw )
42
43#ifndef MAKEFOURCC_WMC
44#define MAKEFOURCC_WMC(ch0, ch1, ch2, ch3) \
45        ((uint32)(uint8)(ch0) | ((uint32)(uint8)(ch1) << 8) |   \
46        ((uint32)(uint8)(ch2) << 16) | ((uint32)(uint8)(ch3) << 24 ))
47
48#define mmioFOURCC_WMC(ch0, ch1, ch2, ch3)  MAKEFOURCC_WMC(ch0, ch1, ch2, ch3)
49#endif
50
51#define FOURCC_WMV2     mmioFOURCC_WMC('W','M','V','2')
52#define FOURCC_WMV3     mmioFOURCC_WMC('W','M','V','3')
53#define FOURCC_WMVA		mmioFOURCC_WMC('W','M','V','A')
54#define FOURCC_WVC1		mmioFOURCC_WMC('W','V','C','1')
55//For WMVA
56#define ASFBINDING_SIZE                   1   // size of ASFBINDING is 1 byte
57#define FOURCC_MP42		mmioFOURCC_WMC('M','P','4','2')
58#define FOURCC_MP43		mmioFOURCC_WMC('M','P','4','3')
59#define FOURCC_mp42		mmioFOURCC_WMC('m','p','4','2')
60#define FOURCC_mp43		mmioFOURCC_WMC('m','p','4','3')
61
62OSCL_DLL_ENTRY_POINT_DEFAULT()
63
64int32 GetNAL_Config(uint8** bitstream, int32* size);
65
66OSCL_EXPORT_REF int16 ti_video_config_parser(tiVideoConfigParserInputs *aInputs, tiVideoConfigParserOutputs *aOutputs, char* pComponentName)
67{
68    if (aInputs->iMimeType == PVMF_MIME_M4V) //m4v
69    {
70        mp4StreamType psBits;
71        psBits.data = aInputs->inPtr;
72        if (aInputs->inBytes <= 0)
73        {
74            return -1;
75        }
76        psBits.numBytes = aInputs->inBytes;
77        psBits.bytePos = 0;
78        psBits.bitBuf = 0;
79        psBits.dataBitPos = 0;
80        psBits.bitPos = 32;
81
82        int32 width, height, display_width, display_height = 0;
83        int32 profile_level = 0;
84        int16 retval = 0;
85        retval = iDecodeVOLHeader(&psBits, &width, &height, &display_width, &display_height, &profile_level);
86        if (retval != 0)
87        {
88            return retval;
89        }
90        aOutputs->width  = (uint32)display_width;
91        aOutputs->height = (uint32)display_height;
92        aOutputs->profile = (uint32)profile_level; // for mp4, profile/level info is packed
93        aOutputs->level = 0;
94
95    }
96    else if (aInputs->iMimeType == PVMF_MIME_H2631998 ||
97             aInputs->iMimeType == PVMF_MIME_H2632000)//h263
98    {
99        // Nothing to do for h263
100        aOutputs->width  = 0;
101        aOutputs->height = 0;
102        aOutputs->profile = 0;
103        aOutputs->level = 0;
104    }
105    else if (aInputs->iMimeType == PVMF_MIME_H264_VIDEO ||
106             aInputs->iMimeType == PVMF_MIME_H264_VIDEO_MP4) //avc
107    {
108        int32 width, height, display_width, display_height = 0;
109        int32 profile_idc, level_idc = 0;
110        uint32 entropy_coding_mode_flag = 0;
111
112        uint8 *tp = aInputs->inPtr;
113
114        if (aInputs->inBytes > 1)
115        {
116            if (tp[0] == 0 && tp[1] == 0)
117            {
118                // ByteStream Format
119                uint8* tmp_ptr = tp;
120                uint8* buffer_begin = tp;
121                int16 length = 0;
122                int initbufsize = aInputs->inBytes;
123                int tConfigSize = 0;
124                do
125                {
126                    tmp_ptr += length;
127                    length = GetNAL_Config(&tmp_ptr, &initbufsize);
128                    buffer_begin[0] = length & 0xFF;
129                    buffer_begin[1] = (length >> 8) & 0xFF;
130                    oscl_memcpy(buffer_begin + 2, tmp_ptr, length);
131                    buffer_begin += (length + 2);
132                    tConfigSize += (length + 2);
133                }
134                while (initbufsize > 0);
135            }
136        }
137
138        // check codec info and get settings
139        int16 retval;
140        retval = iGetAVCConfigInfo(tp,
141                                   aInputs->inBytes,
142                                   (int*) & width,
143                                   (int*) & height,
144                                   (int*) & display_width,
145                                   (int*) & display_height,
146                                   (int*) & profile_idc,
147                                   (int*) & level_idc,
148                                   (uint*) & entropy_coding_mode_flag);
149        if (retval != 0)
150        {
151            return retval;
152        }
153        aOutputs->width  = (uint32)display_width;
154        aOutputs->height = (uint32)display_height;
155        aOutputs->profile = (uint32)profile_idc;
156        aOutputs->level = (uint32) level_idc;
157
158        /*When 720p and other profiles may be handled by other Video Decoder OMX Component,
159          this will let PV know that it will need to load other compponent*/
160        if ( 0 == oscl_strncmp (pComponentName, TI_VID_DEC, oscl_strlen (TI_VID_DEC)) )
161        {
162            if( ((width > WVGA_MAX_WIDTH) || (height > WVGA_MAX_HEIGHT)) ||
163                (profile_idc != H264_PROFILE_IDC_BASELINE) ||
164                entropy_coding_mode_flag )
165            {
166                return -1;
167            }
168        }
169
170    }
171    else if (aInputs->iMimeType == PVMF_MIME_WMV) //wmv
172    {
173        uint32 dwdat;
174        uint16 wdat;
175        uint8 bdat;
176        uint8 *pData = aInputs->inPtr;
177
178        LoadDWORD(dwdat, pData); // Window width
179        LoadDWORD(dwdat, pData); // Window height
180        LoadBYTE(bdat, pData);
181        LoadWORD(wdat, pData);  // Size of image info.
182
183        // BITMAPINFOHEADER
184        LoadDWORD(dwdat, pData); // Size of BMAPINFOHDR
185        LoadDWORD(dwdat, pData);
186        aOutputs->width = dwdat;
187        LoadDWORD(dwdat, pData);
188        aOutputs->height = dwdat;
189
190        /* WMV1 and WMV2 are not supported. Rejected here. */
191        /* Code to Check if comp is WMV1 then return not supported */
192        pData += 4;
193        LoadDWORD(dwdat, pData);
194        uint32 NewCompression = dwdat;
195        uint32 NewSeqHeader = 0;
196        uint32 NewProfile = 0;
197        // in case of WMV store "Compression Type as Level"
198        aOutputs->level = NewCompression;
199
200        if (NewCompression != FOURCC_WMV2 &&
201                NewCompression != FOURCC_WMV3 &&
202                NewCompression != FOURCC_WVC1 &&
203                NewCompression != FOURCC_WMVA &&
204                NewCompression != FOURCC_MP42 &&
205                NewCompression != FOURCC_MP43 &&
206                NewCompression != FOURCC_mp42 &&
207                NewCompression != FOURCC_mp43)
208        {
209            return -1;
210        }
211        // get profile etc.
212        // Check sequence header
213        switch (NewCompression)
214        {
215            case FOURCC_WMV3:
216            {
217                // start fresh
218                pData = aInputs->inPtr;
219                pData += (11 + 40); //sizeof(BITMAPINFOHEADER); // position to sequence header
220
221                LoadDWORD(dwdat, pData);
222                NewSeqHeader = dwdat; // this is little endian read sequence header
223
224                NewProfile = (NewSeqHeader & 0xC0) >> 6; // 0 - simple , 1- main, 3 - complex, 2-forbidden
225
226                break;
227            }
228            case FOURCC_WMVA:
229            {
230                pData = aInputs->inPtr;
231                pData += (11 + 40 + ASFBINDING_SIZE); //sizeof(BITMAPINFOHEADER); // position to sequence header
232
233                LoadDWORD(dwdat, pData); // prefix	// this is little endian read sequence header
234                LoadDWORD(dwdat, pData);
235                NewSeqHeader = dwdat;
236
237                NewProfile = (NewSeqHeader & 0xC0) >> 6; // this must be 3
238            }
239            break;
240
241            default:
242
243                NewProfile = 0;
244                break;
245        }
246
247        aOutputs->profile = NewProfile;
248
249    }
250    else
251    {
252        return -1;
253    }
254    return 0;
255}
256
257
258/* This function finds a nal from the SC's, moves the bitstream pointer to the beginning of the NAL unit, returns the
259size of the NAL, and at the same time, updates the remaining size in the bitstream buffer that is passed in */
260int32 GetNAL_Config(uint8** bitstream, int32* size)
261{
262    int i = 0;
263    int j;
264    uint8* nal_unit = *bitstream;
265    int count = 0;
266
267    /* find SC at the beginning of the NAL */
268    while (nal_unit[i++] == 0 && i < *size)
269    {
270    }
271
272    if (nal_unit[i-1] == 1)
273    {
274        *bitstream = nal_unit + i;
275    }
276    else
277    {
278        j = *size;
279        *size = 0;
280        return j;  // no SC at the beginning, not supposed to happen
281    }
282
283    j = i;
284
285    /* found the SC at the beginning of the NAL, now find the SC at the beginning of the next NAL */
286    while (i < *size)
287    {
288        if (count == 2 && nal_unit[i] == 0x01)
289        {
290            i -= 2;
291            break;
292        }
293
294        if (nal_unit[i])
295            count = 0;
296        else
297            count++;
298        i++;
299    }
300
301    *size -= i;
302    return (i -j);
303}
304