blob: 0e1aa1d59c8afff1017682a4de202fd40cbdb20f [file] [log] [blame]
/* ------------------------------------------------------------------
* Copyright (C) 1998-2009 PacketVideo
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied.
* See the License for the specific language governing permissions
* and limitations under the License.
* -------------------------------------------------------------------
*/
#include "ti_video_config_parser.h"
#include "ti_m4v_config_parser.h"
#include "oscl_mem.h"
#include "oscl_dll.h"
#define GetUnalignedWord( pb, w ) \
(w) = ((uint16) *(pb + 1) << 8) + *pb;
#define GetUnalignedDword( pb, dw ) \
(dw) = ((uint32) *(pb + 3) << 24) + \
((uint32) *(pb + 2) << 16) + \
((uint16) *(pb + 1) << 8) + *pb;
#define GetUnalignedWordEx( pb, w ) GetUnalignedWord( pb, w ); (pb) += sizeof(uint16);
#define GetUnalignedDwordEx( pb, dw ) GetUnalignedDword( pb, dw ); (pb) += sizeof(uint32);
#define GetUnalignedQwordEx( pb, qw ) GetUnalignedQword( pb, qw ); (pb) += sizeof(uint64);
#define LoadBYTE( b, p ) b = *(uint8 *)p; p += sizeof( uint8 )
#define LoadWORD( w, p ) GetUnalignedWordEx( p, w )
#define LoadDWORD( dw, p ) GetUnalignedDwordEx( p, dw )
#define LoadQWORD( qw, p ) GetUnalignedQwordEx( p, qw )
#ifndef MAKEFOURCC_WMC
#define MAKEFOURCC_WMC(ch0, ch1, ch2, ch3) \
((uint32)(uint8)(ch0) | ((uint32)(uint8)(ch1) << 8) | \
((uint32)(uint8)(ch2) << 16) | ((uint32)(uint8)(ch3) << 24 ))
#define mmioFOURCC_WMC(ch0, ch1, ch2, ch3) MAKEFOURCC_WMC(ch0, ch1, ch2, ch3)
#endif
#define FOURCC_WMV2 mmioFOURCC_WMC('W','M','V','2')
#define FOURCC_WMV3 mmioFOURCC_WMC('W','M','V','3')
#define FOURCC_WMVA mmioFOURCC_WMC('W','M','V','A')
#define FOURCC_WVC1 mmioFOURCC_WMC('W','V','C','1')
//For WMVA
#define ASFBINDING_SIZE 1 // size of ASFBINDING is 1 byte
#define FOURCC_MP42 mmioFOURCC_WMC('M','P','4','2')
#define FOURCC_MP43 mmioFOURCC_WMC('M','P','4','3')
#define FOURCC_mp42 mmioFOURCC_WMC('m','p','4','2')
#define FOURCC_mp43 mmioFOURCC_WMC('m','p','4','3')
OSCL_DLL_ENTRY_POINT_DEFAULT()
int32 GetNAL_Config(uint8** bitstream, int32* size);
OSCL_EXPORT_REF int16 ti_video_config_parser(tiVideoConfigParserInputs *aInputs, tiVideoConfigParserOutputs *aOutputs, char *pComponentName)
{
if (aInputs->iMimeType == PVMF_MIME_M4V) //m4v
{
mp4StreamType psBits;
psBits.data = aInputs->inPtr;
if (aInputs->inBytes <= 0)
{
return -1;
}
psBits.numBytes = aInputs->inBytes;
psBits.bytePos = 0;
psBits.bitBuf = 0;
psBits.dataBitPos = 0;
psBits.bitPos = 32;
int32 width, height, display_width, display_height = 0;
int32 profile_level = 0;
int16 retval = 0;
retval = iDecodeVOLHeader(&psBits, &width, &height, &display_width, &display_height, &profile_level);
if (retval != 0)
{
return retval;
}
aOutputs->width = (uint32)display_width;
aOutputs->height = (uint32)display_height;
aOutputs->profile = (uint32)profile_level; // for mp4, profile/level info is packed
aOutputs->level = 0;
/* TI Video Decoder supports up to WVGA 864x480 resolutions, PV should
* use another component to render higher resolutions */
if ((width > WVGA_MAX_WIDTH || height > WVGA_MAX_HEIGHT) && 0 == oscl_strncmp (pComponentName, TI_VID_DEC, oscl_strlen (TI_VID_DEC)))
{
return -1;
}
}
else if (aInputs->iMimeType == PVMF_MIME_H2631998 ||
aInputs->iMimeType == PVMF_MIME_H2632000)//h263
{
// Nothing to do for h263
aOutputs->width = 0;
aOutputs->height = 0;
aOutputs->profile = 0;
aOutputs->level = 0;
}
else if (aInputs->iMimeType == PVMF_MIME_H264_VIDEO ||
aInputs->iMimeType == PVMF_MIME_H264_VIDEO_MP4) //avc
{
int32 width, height, display_width, display_height = 0;
int32 profile_idc, level_idc = 0;
uint8 *tp = aInputs->inPtr;
if (aInputs->inBytes > 1)
{
if (tp[0] == 0 && tp[1] == 0)
{
// ByteStream Format
uint8* tmp_ptr = tp;
uint8* buffer_begin = tp;
int16 length = 0;
int initbufsize = aInputs->inBytes;
int tConfigSize = 0;
do
{
tmp_ptr += length;
length = GetNAL_Config(&tmp_ptr, &initbufsize);
buffer_begin[0] = length & 0xFF;
buffer_begin[1] = (length >> 8) & 0xFF;
oscl_memcpy(buffer_begin + 2, tmp_ptr, length);
buffer_begin += (length + 2);
tConfigSize += (length + 2);
}
while (initbufsize > 0);
}
}
// check codec info and get settings
int16 retval;
retval = iGetAVCConfigInfo(tp,
aInputs->inBytes,
(int*) & width,
(int*) & height,
(int*) & display_width,
(int*) & display_height,
(int*) & profile_idc,
(int*) & level_idc);
if (retval != 0)
{
return retval;
}
aOutputs->width = (uint32)display_width;
aOutputs->height = (uint32)display_height;
aOutputs->profile = (uint32)profile_idc;
aOutputs->level = (uint32) level_idc;
}
else if (aInputs->iMimeType == PVMF_MIME_WMV) //wmv
{
uint32 dwdat;
uint16 wdat;
uint8 bdat;
uint8 *pData = aInputs->inPtr;
LoadDWORD(dwdat, pData); // Window width
LoadDWORD(dwdat, pData); // Window height
LoadBYTE(bdat, pData);
LoadWORD(wdat, pData); // Size of image info.
// BITMAPINFOHEADER
LoadDWORD(dwdat, pData); // Size of BMAPINFOHDR
LoadDWORD(dwdat, pData);
aOutputs->width = dwdat;
LoadDWORD(dwdat, pData);
aOutputs->height = dwdat;
/* WMV1 and WMV2 are not supported. Rejected here. */
/* Code to Check if comp is WMV1 then return not supported */
pData += 4;
LoadDWORD(dwdat, pData);
uint32 NewCompression = dwdat;
uint32 NewSeqHeader = 0;
uint32 NewProfile = 0;
// in case of WMV store "Compression Type as Level"
aOutputs->level = NewCompression;
if (NewCompression != FOURCC_WMV2 &&
NewCompression != FOURCC_WMV3 &&
NewCompression != FOURCC_WVC1 &&
NewCompression != FOURCC_WMVA &&
NewCompression != FOURCC_MP42 &&
NewCompression != FOURCC_MP43 &&
NewCompression != FOURCC_mp42 &&
NewCompression != FOURCC_mp43)
{
return -1;
}
// get profile etc.
// Check sequence header
switch (NewCompression)
{
case FOURCC_WMV3:
{
// start fresh
pData = aInputs->inPtr;
pData += (11 + 40); //sizeof(BITMAPINFOHEADER); // position to sequence header
LoadDWORD(dwdat, pData);
NewSeqHeader = dwdat; // this is little endian read sequence header
NewProfile = (NewSeqHeader & 0xC0) >> 6; // 0 - simple , 1- main, 3 - complex, 2-forbidden
break;
}
case FOURCC_WMVA:
{
pData = aInputs->inPtr;
pData += (11 + 40 + ASFBINDING_SIZE); //sizeof(BITMAPINFOHEADER); // position to sequence header
LoadDWORD(dwdat, pData); // prefix // this is little endian read sequence header
LoadDWORD(dwdat, pData);
NewSeqHeader = dwdat;
NewProfile = (NewSeqHeader & 0xC0) >> 6; // this must be 3
}
break;
default:
NewProfile = 0;
break;
}
aOutputs->profile = NewProfile;
}
else
{
return -1;
}
return 0;
}
/* This function finds a nal from the SC's, moves the bitstream pointer to the beginning of the NAL unit, returns the
size of the NAL, and at the same time, updates the remaining size in the bitstream buffer that is passed in */
int32 GetNAL_Config(uint8** bitstream, int32* size)
{
int i = 0;
int j;
uint8* nal_unit = *bitstream;
int count = 0;
/* find SC at the beginning of the NAL */
while (nal_unit[i++] == 0 && i < *size)
{
}
if (nal_unit[i-1] == 1)
{
*bitstream = nal_unit + i;
}
else
{
j = *size;
*size = 0;
return j; // no SC at the beginning, not supposed to happen
}
j = i;
/* found the SC at the beginning of the NAL, now find the SC at the beginning of the next NAL */
while (i < *size)
{
if (count == 2 && nal_unit[i] == 0x01)
{
i -= 2;
break;
}
if (nal_unit[i])
count = 0;
else
count++;
i++;
}
*size -= i;
return (i -j);
}