Initial import

This commit is contained in:
huceke 2012-03-22 07:31:01 +01:00
commit 306e265019
72 changed files with 23271 additions and 0 deletions

911
BitstreamConverter.cpp Normal file
View file

@ -0,0 +1,911 @@
/*
* Copyright (C) 2010 Team XBMC
* http://www.xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with XBMC; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#ifndef UINT16_MAX
#define UINT16_MAX (65535U)
#endif
#include "BitstreamConverter.h"
void CBitstreamConverter::bits_reader_set( bits_reader_t *br, uint8_t *buf, int len )
{
br->buffer = br->start = buf;
br->offbits = 0;
br->length = len;
br->oflow = 0;
}
uint32_t CBitstreamConverter::read_bits( bits_reader_t *br, int nbits )
{
int i, nbytes;
uint32_t ret = 0;
uint8_t *buf;
buf = br->buffer;
nbytes = (br->offbits + nbits)/8;
if ( ((br->offbits + nbits) %8 ) > 0 )
nbytes++;
if ( (buf + nbytes) > (br->start + br->length) ) {
br->oflow = 1;
return 0;
}
for ( i=0; i<nbytes; i++ )
ret += buf[i]<<((nbytes-i-1)*8);
i = (4-nbytes)*8+br->offbits;
ret = ((ret<<i)>>i)>>((nbytes*8)-nbits-br->offbits);
br->offbits += nbits;
br->buffer += br->offbits / 8;
br->offbits %= 8;
return ret;
}
void CBitstreamConverter::skip_bits( bits_reader_t *br, int nbits )
{
br->offbits += nbits;
br->buffer += br->offbits / 8;
br->offbits %= 8;
if ( br->buffer > (br->start + br->length) ) {
br->oflow = 1;
}
}
uint32_t CBitstreamConverter::get_bits( bits_reader_t *br, int nbits )
{
int i, nbytes;
uint32_t ret = 0;
uint8_t *buf;
buf = br->buffer;
nbytes = (br->offbits + nbits)/8;
if ( ((br->offbits + nbits) %8 ) > 0 )
nbytes++;
if ( (buf + nbytes) > (br->start + br->length) ) {
br->oflow = 1;
return 0;
}
for ( i=0; i<nbytes; i++ )
ret += buf[i]<<((nbytes-i-1)*8);
i = (4-nbytes)*8+br->offbits;
ret = ((ret<<i)>>i)>>((nbytes*8)-nbits-br->offbits);
return ret;
}
////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////
// GStreamer h264 parser
// Copyright (C) 2005 Michal Benes <michal.benes@itonis.tv>
// (C) 2008 Wim Taymans <wim.taymans@gmail.com>
// gsth264parse.c:
// * License as published by the Free Software Foundation; either
// * version 2.1 of the License, or (at your option) any later version.
void CBitstreamConverter::nal_bs_init(nal_bitstream *bs, const uint8_t *data, size_t size)
{
bs->data = data;
bs->end = data + size;
bs->head = 0;
// fill with something other than 0 to detect
// emulation prevention bytes
bs->cache = 0xffffffff;
}
uint32_t CBitstreamConverter::nal_bs_read(nal_bitstream *bs, int n)
{
uint32_t res = 0;
int shift;
if (n == 0)
return res;
// fill up the cache if we need to
while (bs->head < n)
{
uint8_t a_byte;
bool check_three_byte;
check_three_byte = true;
next_byte:
if (bs->data >= bs->end)
{
// we're at the end, can't produce more than head number of bits
n = bs->head;
break;
}
// get the byte, this can be an emulation_prevention_three_byte that we need
// to ignore.
a_byte = *bs->data++;
if (check_three_byte && a_byte == 0x03 && ((bs->cache & 0xffff) == 0))
{
// next byte goes unconditionally to the cache, even if it's 0x03
check_three_byte = false;
goto next_byte;
}
// shift bytes in cache, moving the head bits of the cache left
bs->cache = (bs->cache << 8) | a_byte;
bs->head += 8;
}
// bring the required bits down and truncate
if ((shift = bs->head - n) > 0)
res = bs->cache >> shift;
else
res = bs->cache;
// mask out required bits
if (n < 32)
res &= (1 << n) - 1;
bs->head = shift;
return res;
}
bool CBitstreamConverter::nal_bs_eos(nal_bitstream *bs)
{
return (bs->data >= bs->end) && (bs->head == 0);
}
// read unsigned Exp-Golomb code
int CBitstreamConverter::nal_bs_read_ue(nal_bitstream *bs)
{
int i = 0;
while (nal_bs_read(bs, 1) == 0 && !nal_bs_eos(bs) && i < 32)
i++;
return ((1 << i) - 1 + nal_bs_read(bs, i));
}
void CBitstreamConverter::parseh264_sps(uint8_t *sps, uint32_t sps_size, bool *interlaced, int32_t *max_ref_frames)
{
nal_bitstream bs;
sps_info_struct sps_info;
nal_bs_init(&bs, sps, sps_size);
sps_info.profile_idc = nal_bs_read(&bs, 8);
nal_bs_read(&bs, 1); // constraint_set0_flag
nal_bs_read(&bs, 1); // constraint_set1_flag
nal_bs_read(&bs, 1); // constraint_set2_flag
nal_bs_read(&bs, 1); // constraint_set3_flag
nal_bs_read(&bs, 4); // reserved
sps_info.level_idc = nal_bs_read(&bs, 8);
sps_info.sps_id = nal_bs_read_ue(&bs);
if (sps_info.profile_idc == 100 ||
sps_info.profile_idc == 110 ||
sps_info.profile_idc == 122 ||
sps_info.profile_idc == 244 ||
sps_info.profile_idc == 44 ||
sps_info.profile_idc == 83 ||
sps_info.profile_idc == 86)
{
sps_info.chroma_format_idc = nal_bs_read_ue(&bs);
if (sps_info.chroma_format_idc == 3)
sps_info.separate_colour_plane_flag = nal_bs_read(&bs, 1);
sps_info.bit_depth_luma_minus8 = nal_bs_read_ue(&bs);
sps_info.bit_depth_chroma_minus8 = nal_bs_read_ue(&bs);
sps_info.qpprime_y_zero_transform_bypass_flag = nal_bs_read(&bs, 1);
sps_info.seq_scaling_matrix_present_flag = nal_bs_read (&bs, 1);
if (sps_info.seq_scaling_matrix_present_flag)
{
/* TODO: unfinished */
}
}
sps_info.log2_max_frame_num_minus4 = nal_bs_read_ue(&bs);
if (sps_info.log2_max_frame_num_minus4 > 12)
{ // must be between 0 and 12
return;
}
sps_info.pic_order_cnt_type = nal_bs_read_ue(&bs);
if (sps_info.pic_order_cnt_type == 0)
{
sps_info.log2_max_pic_order_cnt_lsb_minus4 = nal_bs_read_ue(&bs);
}
else if (sps_info.pic_order_cnt_type == 1)
{ // TODO: unfinished
/*
delta_pic_order_always_zero_flag = gst_nal_bs_read (bs, 1);
offset_for_non_ref_pic = gst_nal_bs_read_se (bs);
offset_for_top_to_bottom_field = gst_nal_bs_read_se (bs);
num_ref_frames_in_pic_order_cnt_cycle = gst_nal_bs_read_ue (bs);
for( i = 0; i < num_ref_frames_in_pic_order_cnt_cycle; i++ )
offset_for_ref_frame[i] = gst_nal_bs_read_se (bs);
*/
}
sps_info.max_num_ref_frames = nal_bs_read_ue(&bs);
sps_info.gaps_in_frame_num_value_allowed_flag = nal_bs_read(&bs, 1);
sps_info.pic_width_in_mbs_minus1 = nal_bs_read_ue(&bs);
sps_info.pic_height_in_map_units_minus1 = nal_bs_read_ue(&bs);
sps_info.frame_mbs_only_flag = nal_bs_read(&bs, 1);
if (!sps_info.frame_mbs_only_flag)
sps_info.mb_adaptive_frame_field_flag = nal_bs_read(&bs, 1);
sps_info.direct_8x8_inference_flag = nal_bs_read(&bs, 1);
sps_info.frame_cropping_flag = nal_bs_read(&bs, 1);
if (sps_info.frame_cropping_flag)
{
sps_info.frame_crop_left_offset = nal_bs_read_ue(&bs);
sps_info.frame_crop_right_offset = nal_bs_read_ue(&bs);
sps_info.frame_crop_top_offset = nal_bs_read_ue(&bs);
sps_info.frame_crop_bottom_offset = nal_bs_read_ue(&bs);
}
*interlaced = !sps_info.frame_mbs_only_flag;
*max_ref_frames = sps_info.max_num_ref_frames;
}
const uint8_t *CBitstreamConverter::avc_find_startcode_internal(const uint8_t *p, const uint8_t *end)
{
const uint8_t *a = p + 4 - ((intptr_t)p & 3);
for (end -= 3; p < a && p < end; p++)
{
if (p[0] == 0 && p[1] == 0 && p[2] == 1)
return p;
}
for (end -= 3; p < end; p += 4)
{
uint32_t x = *(const uint32_t*)p;
if ((x - 0x01010101) & (~x) & 0x80808080) // generic
{
if (p[1] == 0)
{
if (p[0] == 0 && p[2] == 1)
return p;
if (p[2] == 0 && p[3] == 1)
return p+1;
}
if (p[3] == 0)
{
if (p[2] == 0 && p[4] == 1)
return p+2;
if (p[4] == 0 && p[5] == 1)
return p+3;
}
}
}
for (end += 3; p < end; p++)
{
if (p[0] == 0 && p[1] == 0 && p[2] == 1)
return p;
}
return end + 3;
}
const uint8_t *CBitstreamConverter::avc_find_startcode(const uint8_t *p, const uint8_t *end)
{
const uint8_t *out= avc_find_startcode_internal(p, end);
if (p<out && out<end && !out[-1])
out--;
return out;
}
const int CBitstreamConverter::avc_parse_nal_units(ByteIOContext *pb, const uint8_t *buf_in, int size)
{
const uint8_t *p = buf_in;
const uint8_t *end = p + size;
const uint8_t *nal_start, *nal_end;
size = 0;
nal_start = avc_find_startcode(p, end);
for (;;) {
while (nal_start < end && !*(nal_start++));
if (nal_start == end)
break;
nal_end = avc_find_startcode(nal_start, end);
m_dllAvFormat->put_be32(pb, nal_end - nal_start);
m_dllAvFormat->put_buffer(pb, nal_start, nal_end - nal_start);
size += 4 + nal_end - nal_start;
nal_start = nal_end;
}
return size;
}
const int CBitstreamConverter::avc_parse_nal_units_buf(const uint8_t *buf_in, uint8_t **buf, int *size)
{
ByteIOContext *pb;
int ret = m_dllAvFormat->url_open_dyn_buf(&pb);
if (ret < 0)
return ret;
avc_parse_nal_units(pb, buf_in, *size);
m_dllAvUtil->av_freep(buf);
*size = m_dllAvFormat->url_close_dyn_buf(pb, buf);
return 0;
}
const int CBitstreamConverter::isom_write_avcc(ByteIOContext *pb, const uint8_t *data, int len)
{
// extradata from bytestream h264, convert to avcC atom data for bitstream
if (len > 6)
{
/* check for h264 start code */
if (OMX_RB32(data) == 0x00000001 || OMX_RB24(data) == 0x000001)
{
uint8_t *buf=NULL, *end, *start;
uint32_t sps_size=0, pps_size=0;
uint8_t *sps=0, *pps=0;
int ret = avc_parse_nal_units_buf(data, &buf, &len);
if (ret < 0)
return ret;
start = buf;
end = buf + len;
/* look for sps and pps */
while (end - buf > 4)
{
uint32_t size;
uint8_t nal_type;
size = FFMIN(OMX_RB32(buf), end - buf - 4);
buf += 4;
nal_type = buf[0] & 0x1f;
if (nal_type == 7) /* SPS */
{
sps = buf;
sps_size = size;
}
else if (nal_type == 8) /* PPS */
{
pps = buf;
pps_size = size;
}
buf += size;
}
if (!sps || !pps || sps_size < 4 || sps_size > UINT16_MAX || pps_size > UINT16_MAX)
assert(0);
m_dllAvFormat->put_byte(pb, 1); /* version */
m_dllAvFormat->put_byte(pb, sps[1]); /* profile */
m_dllAvFormat->put_byte(pb, sps[2]); /* profile compat */
m_dllAvFormat->put_byte(pb, sps[3]); /* level */
m_dllAvFormat->put_byte(pb, 0xff); /* 6 bits reserved (111111) + 2 bits nal size length - 1 (11) */
m_dllAvFormat->put_byte(pb, 0xe1); /* 3 bits reserved (111) + 5 bits number of sps (00001) */
m_dllAvFormat->put_be16(pb, sps_size);
m_dllAvFormat->put_buffer(pb, sps, sps_size);
if (pps)
{
m_dllAvFormat->put_byte(pb, 1); /* number of pps */
m_dllAvFormat->put_be16(pb, pps_size);
m_dllAvFormat->put_buffer(pb, pps, pps_size);
}
m_dllAvUtil->av_free(start);
}
else
{
m_dllAvFormat->put_buffer(pb, data, len);
}
}
return 0;
}
CBitstreamConverter::CBitstreamConverter()
{
m_convert_bitstream = false;
m_convertBuffer = NULL;
m_convertSize = 0;
m_inputBuffer = NULL;
m_inputSize = 0;
m_to_annexb = false;
m_extradata = NULL;
m_extrasize = 0;
m_convert_3byteTo4byteNALSize = false;
m_dllAvUtil = NULL;
m_dllAvFormat = NULL;
m_convert_bytestream = false;
m_convert_vc1 = false;
}
CBitstreamConverter::~CBitstreamConverter()
{
Close();
}
bool CBitstreamConverter::Open(enum CodecID codec, uint8_t *in_extradata, int in_extrasize, bool to_annexb)
{
m_to_annexb = to_annexb;
m_convert_vc1 = false;
m_codec = codec;
switch(codec)
{
case CODEC_ID_VC1:
m_extradata = (uint8_t *)malloc(in_extrasize);
memcpy(m_extradata, in_extradata, in_extrasize);
m_extrasize = in_extrasize;
m_dllAvUtil = new DllAvUtil;
m_dllAvFormat = new DllAvFormat;
if (!m_dllAvUtil->Load() || !m_dllAvFormat->Load())
return false;
return true;
break;
case CODEC_ID_H264:
if (in_extrasize < 7 || in_extradata == NULL)
{
CLog::Log(LOGERROR, "CBitstreamConverter::Open avcC data too small or missing\n");
return false;
}
// valid avcC data (bitstream) always starts with the value 1 (version)
if(m_to_annexb)
{
if ( *(char*)in_extradata == 1 )
{
CLog::Log(LOGINFO, "CBitstreamConverter::Open bitstream to annexb init\n");
m_convert_bitstream = BitstreamConvertInit(in_extradata, in_extrasize);
return true;
}
}
else
{
// valid avcC atom data always starts with the value 1 (version)
if ( *in_extradata != 1 )
{
if (in_extradata[0] == 0 && in_extradata[1] == 0 && in_extradata[2] == 0 && in_extradata[3] == 1)
{
CLog::Log(LOGINFO, "CBitstreamConverter::Open annexb to bitstream init\n");
// video content is from x264 or from bytestream h264 (AnnexB format)
// NAL reformating to bitstream format needed
m_dllAvUtil = new DllAvUtil;
m_dllAvFormat = new DllAvFormat;
if (!m_dllAvUtil->Load() || !m_dllAvFormat->Load())
return false;
ByteIOContext *pb;
if (m_dllAvFormat->url_open_dyn_buf(&pb) < 0)
return false;
m_convert_bytestream = true;
// create a valid avcC atom data from ffmpeg's extradata
isom_write_avcc(pb, in_extradata, in_extrasize);
// unhook from ffmpeg's extradata
in_extradata = NULL;
// extract the avcC atom data into extradata then write it into avcCData for VDADecoder
in_extrasize = m_dllAvFormat->url_close_dyn_buf(pb, &in_extradata);
// make a copy of extradata contents
m_extradata = (uint8_t *)malloc(in_extrasize);
memcpy(m_extradata, in_extradata, in_extrasize);
m_extrasize = in_extrasize;
// done with the converted extradata, we MUST free using av_free
m_dllAvUtil->av_free(in_extradata);
return true;
}
else
{
CLog::Log(LOGNOTICE, "CBitstreamConverter::Open invalid avcC atom data");
return false;
}
}
else
{
if (in_extradata[4] == 0xFE)
{
CLog::Log(LOGINFO, "CBitstreamConverter::Open annexb to bitstream init 3 byte to 4 byte nal\n");
// video content is from so silly encoder that think 3 byte NAL sizes
// are valid, setup to convert 3 byte NAL sizes to 4 byte.
m_dllAvUtil = new DllAvUtil;
m_dllAvFormat = new DllAvFormat;
if (!m_dllAvUtil->Load() || !m_dllAvFormat->Load())
return false;
in_extradata[4] = 0xFF;
m_convert_3byteTo4byteNALSize = true;
m_extradata = (uint8_t *)malloc(in_extrasize);
memcpy(m_extradata, in_extradata, in_extrasize);
m_extrasize = in_extrasize;
return true;
}
}
}
return false;
break;
default:
return false;
break;
}
return false;
}
void CBitstreamConverter::Close(void)
{
if (m_convert_bitstream)
{
if (m_sps_pps_context.sps_pps_data)
{
free(m_sps_pps_context.sps_pps_data);
m_sps_pps_context.sps_pps_data = NULL;
}
if(m_convertBuffer)
free(m_convertBuffer);
m_convertSize = 0;
}
if (m_convert_bytestream || m_convert_vc1)
{
if(m_convertBuffer)
{
m_dllAvUtil->av_free(m_convertBuffer);
m_convertBuffer = NULL;
}
m_convertSize = 0;
}
if(m_extradata)
free(m_extradata);
m_extradata = NULL;
m_extrasize = 0;
m_inputBuffer = NULL;
m_inputSize = 0;
m_convert_3byteTo4byteNALSize = false;
m_convert_bitstream = false;
if (m_dllAvUtil)
{
delete m_dllAvUtil;
m_dllAvUtil = NULL;
}
if (m_dllAvFormat)
{
delete m_dllAvFormat;
m_dllAvFormat = NULL;
}
}
bool CBitstreamConverter::Convert(uint8_t *pData, int iSize)
{
if(m_convertBuffer)
free(m_convertBuffer);
m_convertBuffer = NULL;
m_convertSize = 0;
m_inputBuffer = NULL;
m_inputSize = 0;
if (pData)
{
if(m_codec == CODEC_ID_H264)
{
if(m_to_annexb)
{
int demuxer_bytes = iSize;
uint8_t *demuxer_content = pData;
if (m_convert_bitstream)
{
// convert demuxer packet from bitstream to bytestream (AnnexB)
int bytestream_size = 0;
uint8_t *bytestream_buff = NULL;
BitstreamConvert(demuxer_content, demuxer_bytes, &bytestream_buff, &bytestream_size);
if (bytestream_buff && (bytestream_size > 0))
{
m_convertSize = bytestream_size;
m_convertBuffer = bytestream_buff;
}
else
{
Close();
m_inputBuffer = pData;
m_inputSize = iSize;
CLog::Log(LOGERROR, "CBitstreamConverter::Convert error converting. disable converter\n");
}
}
else
{
m_inputBuffer = pData;
m_inputSize = iSize;
}
return true;
}
else
{
m_inputBuffer = pData;
m_inputSize = iSize;
if (m_convert_bytestream)
{
if(m_convertBuffer)
{
m_dllAvUtil->av_free(m_convertBuffer);
m_convertBuffer = NULL;
}
m_convertSize = 0;
// convert demuxer packet from bytestream (AnnexB) to bitstream
ByteIOContext *pb;
if(m_dllAvFormat->url_open_dyn_buf(&pb) < 0)
{
return false;
}
m_convertSize = avc_parse_nal_units(pb, pData, iSize);
m_convertSize = m_dllAvFormat->url_close_dyn_buf(pb, &m_convertBuffer);
}
else if (m_convert_3byteTo4byteNALSize)
{
if(m_convertBuffer)
{
m_dllAvUtil->av_free(m_convertBuffer);
m_convertBuffer = NULL;
}
m_convertSize = 0;
// convert demuxer packet from 3 byte NAL sizes to 4 byte
ByteIOContext *pb;
if (m_dllAvFormat->url_open_dyn_buf(&pb) < 0)
return false;
uint32_t nal_size;
uint8_t *end = pData + iSize;
uint8_t *nal_start = pData;
while (nal_start < end)
{
nal_size = OMX_RB24(nal_start);
m_dllAvFormat->put_be32(pb, nal_size);
nal_start += 3;
m_dllAvFormat->put_buffer(pb, nal_start, nal_size);
nal_start += nal_size;
}
m_convertSize = m_dllAvFormat->url_close_dyn_buf(pb, &m_convertBuffer);
}
return true;
}
}
else if (m_codec == CODEC_ID_VC1)
{
if(!(iSize >= 3 && !pData[0] && !pData[1] && pData[2] == 1) && !m_convert_vc1)
m_convert_vc1 = true;
if(m_convert_vc1)
{
m_inputBuffer = pData;
m_inputSize = iSize;
if(m_convertBuffer)
{
m_dllAvUtil->av_free(m_convertBuffer);
m_convertBuffer = NULL;
}
m_convertSize = 0;
ByteIOContext *pb;
if (m_dllAvFormat->url_open_dyn_buf(&pb) < 0)
return false;
m_dllAvFormat->put_byte(pb, 0);
m_dllAvFormat->put_byte(pb, 0);
m_dllAvFormat->put_byte(pb, !m_convert_vc1 ? 0 : 1);
m_dllAvFormat->put_byte(pb, !m_convert_vc1 ? 0 : 0xd);
m_dllAvFormat->put_buffer(pb, pData, iSize);
m_convertSize = m_dllAvFormat->url_close_dyn_buf(pb, &m_convertBuffer);
return true;
}
else
{
m_inputBuffer = pData;
m_inputSize = iSize;
return true;
}
}
}
return false;
}
uint8_t *CBitstreamConverter::GetConvertBuffer()
{
if((m_convert_bitstream || m_convert_bytestream || m_convert_3byteTo4byteNALSize || m_convert_vc1) && m_convertBuffer != NULL)
return m_convertBuffer;
else
return m_inputBuffer;
}
int CBitstreamConverter::GetConvertSize()
{
if((m_convert_bitstream || m_convert_bytestream || m_convert_3byteTo4byteNALSize || m_convert_vc1) && m_convertBuffer != NULL)
return m_convertSize;
else
return m_inputSize;
}
uint8_t *CBitstreamConverter::GetExtraData()
{
return m_extradata;
}
int CBitstreamConverter::GetExtraSize()
{
return m_extrasize;
}
bool CBitstreamConverter::BitstreamConvertInit(void *in_extradata, int in_extrasize)
{
// based on h264_mp4toannexb_bsf.c (ffmpeg)
// which is Copyright (c) 2007 Benoit Fouet <benoit.fouet@free.fr>
// and Licensed GPL 2.1 or greater
m_sps_pps_size = 0;
m_sps_pps_context.sps_pps_data = NULL;
// nothing to filter
if (!in_extradata || in_extrasize < 6)
return false;
uint16_t unit_size;
uint32_t total_size = 0;
uint8_t *out = NULL, unit_nb, sps_done = 0;
const uint8_t *extradata = (uint8_t*)in_extradata + 4;
static const uint8_t nalu_header[4] = {0, 0, 0, 1};
// retrieve length coded size
m_sps_pps_context.length_size = (*extradata++ & 0x3) + 1;
if (m_sps_pps_context.length_size == 3)
return false;
// retrieve sps and pps unit(s)
unit_nb = *extradata++ & 0x1f; // number of sps unit(s)
if (!unit_nb)
{
unit_nb = *extradata++; // number of pps unit(s)
sps_done++;
}
while (unit_nb--)
{
unit_size = extradata[0] << 8 | extradata[1];
total_size += unit_size + 4;
if ( (extradata + 2 + unit_size) > ((uint8_t*)in_extradata + in_extrasize) )
{
free(out);
return false;
}
out = (uint8_t*)realloc(out, total_size);
if (!out)
return false;
memcpy(out + total_size - unit_size - 4, nalu_header, 4);
memcpy(out + total_size - unit_size, extradata + 2, unit_size);
extradata += 2 + unit_size;
if (!unit_nb && !sps_done++)
unit_nb = *extradata++; // number of pps unit(s)
}
m_sps_pps_context.sps_pps_data = out;
m_sps_pps_context.size = total_size;
m_sps_pps_context.first_idr = 1;
return true;
}
bool CBitstreamConverter::BitstreamConvert(uint8_t* pData, int iSize, uint8_t **poutbuf, int *poutbuf_size)
{
// based on h264_mp4toannexb_bsf.c (ffmpeg)
// which is Copyright (c) 2007 Benoit Fouet <benoit.fouet@free.fr>
// and Licensed GPL 2.1 or greater
uint8_t *buf = pData;
uint32_t buf_size = iSize;
uint8_t unit_type;
int32_t nal_size;
uint32_t cumul_size = 0;
const uint8_t *buf_end = buf + buf_size;
do
{
if (buf + m_sps_pps_context.length_size > buf_end)
goto fail;
if (m_sps_pps_context.length_size == 1)
nal_size = buf[0];
else if (m_sps_pps_context.length_size == 2)
nal_size = buf[0] << 8 | buf[1];
else
nal_size = buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3];
buf += m_sps_pps_context.length_size;
unit_type = *buf & 0x1f;
if (buf + nal_size > buf_end || nal_size < 0)
goto fail;
// prepend only to the first type 5 NAL unit of an IDR picture
if (m_sps_pps_context.first_idr && unit_type == 5)
{
BitstreamAllocAndCopy(poutbuf, poutbuf_size,
m_sps_pps_context.sps_pps_data, m_sps_pps_context.size, buf, nal_size);
m_sps_pps_context.first_idr = 0;
}
else
{
BitstreamAllocAndCopy(poutbuf, poutbuf_size, NULL, 0, buf, nal_size);
if (!m_sps_pps_context.first_idr && unit_type == 1)
m_sps_pps_context.first_idr = 1;
}
buf += nal_size;
cumul_size += nal_size + m_sps_pps_context.length_size;
} while (cumul_size < buf_size);
return true;
fail:
free(*poutbuf);
*poutbuf = NULL;
*poutbuf_size = 0;
return false;
}
void CBitstreamConverter::BitstreamAllocAndCopy( uint8_t **poutbuf, int *poutbuf_size,
const uint8_t *sps_pps, uint32_t sps_pps_size, const uint8_t *in, uint32_t in_size)
{
// based on h264_mp4toannexb_bsf.c (ffmpeg)
// which is Copyright (c) 2007 Benoit Fouet <benoit.fouet@free.fr>
// and Licensed GPL 2.1 or greater
#define CHD_WB32(p, d) { \
((uint8_t*)(p))[3] = (d); \
((uint8_t*)(p))[2] = (d) >> 8; \
((uint8_t*)(p))[1] = (d) >> 16; \
((uint8_t*)(p))[0] = (d) >> 24; }
uint32_t offset = *poutbuf_size;
uint8_t nal_header_size = offset ? 3 : 4;
*poutbuf_size += sps_pps_size + in_size + nal_header_size;
*poutbuf = (uint8_t*)realloc(*poutbuf, *poutbuf_size);
if (sps_pps)
memcpy(*poutbuf + offset, sps_pps, sps_pps_size);
memcpy(*poutbuf + sps_pps_size + nal_header_size + offset, in, in_size);
if (!offset)
{
CHD_WB32(*poutbuf + sps_pps_size, 1);
}
else
{
(*poutbuf + offset + sps_pps_size)[0] = 0;
(*poutbuf + offset + sps_pps_size)[1] = 0;
(*poutbuf + offset + sps_pps_size)[2] = 1;
}
}

172
BitstreamConverter.h Normal file
View file

@ -0,0 +1,172 @@
/*
* Copyright (C) 2010 Team XBMC
* http://www.xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with XBMC; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#ifndef _BITSTREAMCONVERTER_H_
#define _BITSTREAMCONVERTER_H_
#include <stdint.h>
#include "DllAvUtil.h"
#include "DllAvFormat.h"
#include "DllAvFilter.h"
#include "DllAvCodec.h"
#include "DllAvCore.h"
typedef struct {
uint8_t *buffer, *start;
int offbits, length, oflow;
} bits_reader_t;
////////////////////////////////////////////////////////////////////////////////////////////
// TODO: refactor this so as not to need these ffmpeg routines.
// These are not exposed in ffmpeg's API so we dupe them here.
// AVC helper functions for muxers,
// * Copyright (c) 2006 Baptiste Coudurier <baptiste.coudurier@smartjog.com>
// This is part of FFmpeg
// * License as published by the Free Software Foundation; either
// * version 2.1 of the License, or (at your option) any later version.
#define OMX_RB16(x) \
((((const uint8_t*)(x))[0] << 8) | \
((const uint8_t*)(x)) [1])
#define OMX_RB24(x) \
((((const uint8_t*)(x))[0] << 16) | \
(((const uint8_t*)(x))[1] << 8) | \
((const uint8_t*)(x))[2])
#define OMX_RB32(x) \
((((const uint8_t*)(x))[0] << 24) | \
(((const uint8_t*)(x))[1] << 16) | \
(((const uint8_t*)(x))[2] << 8) | \
((const uint8_t*)(x))[3])
#define OMX_WB32(p, d) { \
((uint8_t*)(p))[3] = (d); \
((uint8_t*)(p))[2] = (d) >> 8; \
((uint8_t*)(p))[1] = (d) >> 16; \
((uint8_t*)(p))[0] = (d) >> 24; }
typedef struct
{
const uint8_t *data;
const uint8_t *end;
int head;
uint64_t cache;
} nal_bitstream;
typedef struct
{
int profile_idc;
int level_idc;
int sps_id;
int chroma_format_idc;
int separate_colour_plane_flag;
int bit_depth_luma_minus8;
int bit_depth_chroma_minus8;
int qpprime_y_zero_transform_bypass_flag;
int seq_scaling_matrix_present_flag;
int log2_max_frame_num_minus4;
int pic_order_cnt_type;
int log2_max_pic_order_cnt_lsb_minus4;
int max_num_ref_frames;
int gaps_in_frame_num_value_allowed_flag;
int pic_width_in_mbs_minus1;
int pic_height_in_map_units_minus1;
int frame_mbs_only_flag;
int mb_adaptive_frame_field_flag;
int direct_8x8_inference_flag;
int frame_cropping_flag;
int frame_crop_left_offset;
int frame_crop_right_offset;
int frame_crop_top_offset;
int frame_crop_bottom_offset;
} sps_info_struct;
class CBitstreamConverter
{
public:
CBitstreamConverter();
~CBitstreamConverter();
// Required overrides
static void bits_reader_set( bits_reader_t *br, uint8_t *buf, int len );
static uint32_t read_bits( bits_reader_t *br, int nbits );
static void skip_bits( bits_reader_t *br, int nbits );
static uint32_t get_bits( bits_reader_t *br, int nbits );
bool Open(enum CodecID codec, uint8_t *in_extradata, int in_extrasize, bool to_annexb);
void Close(void);
bool NeedConvert(void) { return m_convert_bitstream; };
bool Convert(uint8_t *pData, int iSize);
uint8_t *GetConvertBuffer(void);
int GetConvertSize();
uint8_t *GetExtraData(void);
int GetExtraSize();
void parseh264_sps(uint8_t *sps, uint32_t sps_size, bool *interlaced, int32_t *max_ref_frames);
protected:
// bytestream (Annex B) to bistream conversion support.
void nal_bs_init(nal_bitstream *bs, const uint8_t *data, size_t size);
uint32_t nal_bs_read(nal_bitstream *bs, int n);
bool nal_bs_eos(nal_bitstream *bs);
int nal_bs_read_ue(nal_bitstream *bs);
const uint8_t *avc_find_startcode_internal(const uint8_t *p, const uint8_t *end);
const uint8_t *avc_find_startcode(const uint8_t *p, const uint8_t *end);
const int avc_parse_nal_units(ByteIOContext *pb, const uint8_t *buf_in, int size);
const int avc_parse_nal_units_buf(const uint8_t *buf_in, uint8_t **buf, int *size);
const int isom_write_avcc(ByteIOContext *pb, const uint8_t *data, int len);
// bitstream to bytestream (Annex B) conversion support.
bool BitstreamConvertInit(void *in_extradata, int in_extrasize);
bool BitstreamConvert(uint8_t* pData, int iSize, uint8_t **poutbuf, int *poutbuf_size);
void BitstreamAllocAndCopy( uint8_t **poutbuf, int *poutbuf_size,
const uint8_t *sps_pps, uint32_t sps_pps_size, const uint8_t *in, uint32_t in_size);
typedef struct omx_bitstream_ctx {
uint8_t length_size;
uint8_t first_idr;
uint8_t *sps_pps_data;
uint32_t size;
} omx_bitstream_ctx;
uint8_t *m_convertBuffer;
int m_convertSize;
uint8_t *m_inputBuffer;
int m_inputSize;
uint32_t m_sps_pps_size;
omx_bitstream_ctx m_sps_pps_context;
bool m_convert_bitstream;
bool m_to_annexb;
bool m_convert_vc1;
uint8_t *m_extradata;
int m_extrasize;
bool m_convert_3byteTo4byteNALSize;
bool m_convert_bytestream;
DllAvUtil *m_dllAvUtil;
DllAvFormat *m_dllAvFormat;
CodecID m_codec;
};
#endif

340
COPYING Normal file
View file

@ -0,0 +1,340 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.

377
DllAvCodec.h Normal file
View file

@ -0,0 +1,377 @@
#pragma once
/*
* Copyright (C) 2005-2010 Team XBMC
* http://www.xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with XBMC; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#if (defined HAVE_CONFIG_H) && (!defined WIN32)
#include "config.h"
#endif
#include "DynamicDll.h"
#include "DllAvCore.h"
#include "utils/log.h"
#ifndef AV_NOWARN_DEPRECATED
#define AV_NOWARN_DEPRECATED
#endif
extern "C" {
#ifndef HAVE_MMX
#define HAVE_MMX
#endif
#ifndef __STDC_CONSTANT_MACROS
#define __STDC_CONSTANT_MACROS
#endif
#ifndef __STDC_LIMIT_MACROS
#define __STDC_LIMIT_MACROS
#endif
#ifndef __GNUC__
#pragma warning(disable:4244)
#endif
#if (defined USE_EXTERNAL_FFMPEG)
#if (defined HAVE_LIBAVCODEC_AVCODEC_H)
#include <libavcodec/avcodec.h>
#if (defined HAVE_LIBAVCODEC_OPT_H)
#include <libavcodec/opt.h>
#endif
#if (defined AVPACKET_IN_AVFORMAT)
#include <libavformat/avformat.h>
#endif
#elif (defined HAVE_FFMPEG_AVCODEC_H)
#include <ffmpeg/avcodec.h>
#include <ffmpeg/opt.h>
#if (defined AVPACKET_IN_AVFORMAT)
#include <ffmpeg/avformat.h>
#endif
#endif
/* From non-public audioconvert.h */
int64_t avcodec_guess_channel_layout(int nb_channels, enum CodecID codec_id, const char *fmt_name);
struct AVAudioConvert;
typedef struct AVAudioConvert AVAudioConvert;
AVAudioConvert *av_audio_convert_alloc(enum AVSampleFormat out_fmt, int out_channels,
enum AVSampleFormat in_fmt, int in_channels,
const float *matrix, int flags);
void av_audio_convert_free(AVAudioConvert *ctx);
int av_audio_convert(AVAudioConvert *ctx,
void * const out[6], const int out_stride[6],
const void * const in[6], const int in_stride[6], int len);
#else
#include "libavcodec/avcodec.h"
#include "libavcodec/audioconvert.h"
#endif
}
/* Some convenience macros introduced at this particular revision of libavcodec.
*/
#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(52,25,0)
#define CH_LAYOUT_5POINT0_BACK (CH_LAYOUT_SURROUND|CH_BACK_LEFT|CH_BACK_RIGHT)
#define CH_LAYOUT_5POINT1_BACK (CH_LAYOUT_5POINT0_BACK|CH_LOW_FREQUENCY)
#undef CH_LAYOUT_7POINT1_WIDE
#define CH_LAYOUT_7POINT1_WIDE (CH_LAYOUT_5POINT1_BACK|\
CH_FRONT_LEFT_OF_CENTER|CH_FRONT_RIGHT_OF_CENTER)
#endif
#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(52,64,0)
// API added on: 2010-03-31
#define AVMediaType CodecType
#define AVMEDIA_TYPE_UNKNOWN CODEC_TYPE_UNKNOWN
#define AVMEDIA_TYPE_VIDEO CODEC_TYPE_VIDEO
#define AVMEDIA_TYPE_AUDIO CODEC_TYPE_AUDIO
#define AVMEDIA_TYPE_DATA CODEC_TYPE_DATA
#define AVMEDIA_TYPE_SUBTITLE CODEC_TYPE_SUBTITLE
#define AVMEDIA_TYPE_ATTACHMENT CODEC_TYPE_ATTACHMENT
#define AVMEDIA_TYPE_NB CODEC_TYPE_NB
#endif
//#include "threads/SingleLock.h"
class DllAvCodecInterface
{
public:
virtual ~DllAvCodecInterface() {}
virtual void avcodec_register_all(void)=0;
virtual void avcodec_flush_buffers(AVCodecContext *avctx)=0;
virtual int avcodec_open_dont_call(AVCodecContext *avctx, AVCodec *codec)=0;
virtual AVCodec *avcodec_find_decoder(enum CodecID id)=0;
virtual AVCodec *avcodec_find_encoder(enum CodecID id)=0;
virtual int avcodec_close_dont_call(AVCodecContext *avctx)=0;
virtual AVFrame *avcodec_alloc_frame(void)=0;
virtual int avpicture_fill(AVPicture *picture, uint8_t *ptr, PixelFormat pix_fmt, int width, int height)=0;
virtual int avcodec_decode_video2(AVCodecContext *avctx, AVFrame *picture, int *got_picture_ptr, AVPacket *avpkt)=0;
virtual int avcodec_decode_audio3(AVCodecContext *avctx, int16_t *samples, int *frame_size_ptr, AVPacket *avpkt)=0;
virtual int avcodec_decode_subtitle2(AVCodecContext *avctx, AVSubtitle *sub, int *got_sub_ptr, AVPacket *avpkt)=0;
virtual int avcodec_encode_audio(AVCodecContext *avctx, uint8_t *buf, int buf_size, const short *samples)=0;
virtual int avpicture_get_size(PixelFormat pix_fmt, int width, int height)=0;
virtual AVCodecContext *avcodec_alloc_context(void)=0;
virtual void avcodec_string(char *buf, int buf_size, AVCodecContext *enc, int encode)=0;
virtual void avcodec_get_context_defaults(AVCodecContext *s)=0;
virtual AVCodecParserContext *av_parser_init(int codec_id)=0;
virtual int av_parser_parse2(AVCodecParserContext *s,AVCodecContext *avctx, uint8_t **poutbuf, int *poutbuf_size,
const uint8_t *buf, int buf_size,
int64_t pts, int64_t dts, int64_t pos)=0;
virtual void av_parser_close(AVCodecParserContext *s)=0;
virtual AVBitStreamFilterContext *av_bitstream_filter_init(const char *name)=0;
virtual int av_bitstream_filter_filter(AVBitStreamFilterContext *bsfc,
AVCodecContext *avctx, const char *args,
uint8_t **poutbuf, int *poutbuf_size,
const uint8_t *buf, int buf_size, int keyframe) =0;
virtual void av_bitstream_filter_close(AVBitStreamFilterContext *bsfc) =0;
virtual void avpicture_free(AVPicture *picture)=0;
virtual void av_free_packet(AVPacket *pkt)=0;
virtual int avpicture_alloc(AVPicture *picture, PixelFormat pix_fmt, int width, int height)=0;
virtual enum PixelFormat avcodec_default_get_format(struct AVCodecContext *s, const enum PixelFormat *fmt)=0;
virtual int avcodec_default_get_buffer(AVCodecContext *s, AVFrame *pic)=0;
virtual void avcodec_default_release_buffer(AVCodecContext *s, AVFrame *pic)=0;
virtual int avcodec_thread_init(AVCodecContext *s, int thread_count)=0;
virtual AVCodec *av_codec_next(AVCodec *c)=0;
virtual AVAudioConvert *av_audio_convert_alloc(enum AVSampleFormat out_fmt, int out_channels,
enum AVSampleFormat in_fmt , int in_channels,
const float *matrix , int flags)=0;
virtual void av_audio_convert_free(AVAudioConvert *ctx)=0;
virtual int av_audio_convert(AVAudioConvert *ctx,
void * const out[6], const int out_stride[6],
const void * const in[6], const int in_stride[6], int len)=0;
virtual int av_dup_packet(AVPacket *pkt)=0;
virtual void av_init_packet(AVPacket *pkt)=0;
virtual int64_t avcodec_guess_channel_layout(int nb_channels, enum CodecID codec_id, const char *fmt_name)=0;
};
#if (defined USE_EXTERNAL_FFMPEG)
// Use direct layer
class DllAvCodec : public DllDynamic, DllAvCodecInterface
{
public:
virtual ~DllAvCodec() {}
virtual void avcodec_register_all()
{
::avcodec_register_all();
}
virtual void avcodec_flush_buffers(AVCodecContext *avctx) { ::avcodec_flush_buffers(avctx); }
virtual int avcodec_open(AVCodecContext *avctx, AVCodec *codec)
{
return ::avcodec_open(avctx, codec);
}
virtual int avcodec_open_dont_call(AVCodecContext *avctx, AVCodec *codec) { *(int *)0x0 = 0; return 0; }
virtual int avcodec_close_dont_call(AVCodecContext *avctx) { *(int *)0x0 = 0; return 0; }
virtual AVCodec *avcodec_find_decoder(enum CodecID id) { return ::avcodec_find_decoder(id); }
virtual AVCodec *avcodec_find_encoder(enum CodecID id) { return ::avcodec_find_encoder(id); }
virtual int avcodec_close(AVCodecContext *avctx)
{
return ::avcodec_close(avctx);
}
virtual AVFrame *avcodec_alloc_frame() { return ::avcodec_alloc_frame(); }
virtual int avpicture_fill(AVPicture *picture, uint8_t *ptr, PixelFormat pix_fmt, int width, int height) { return ::avpicture_fill(picture, ptr, pix_fmt, width, height); }
#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(52,23,0)
// API added on: 2009-04-07
virtual int avcodec_decode_video2(AVCodecContext *avctx, AVFrame *picture, int *got_picture_ptr, AVPacket *avpkt) { return ::avcodec_decode_video2(avctx, picture, got_picture_ptr, avpkt); }
virtual int avcodec_decode_audio3(AVCodecContext *avctx, int16_t *samples, int *frame_size_ptr, AVPacket *avpkt) { return ::avcodec_decode_audio3(avctx, samples, frame_size_ptr, avpkt); }
virtual int avcodec_decode_subtitle2(AVCodecContext *avctx, AVSubtitle *sub, int *got_sub_ptr, AVPacket *avpkt) { return ::avcodec_decode_subtitle2(avctx, sub, got_sub_ptr, avpkt); }
#else
virtual int avcodec_decode_video2(AVCodecContext *avctx, AVFrame *picture, int *got_picture_ptr, AVPacket *avpkt) { return ::avcodec_decode_video(avctx, picture, got_picture_ptr, avpkt->data, avpkt->size); }
virtual int avcodec_decode_audio3(AVCodecContext *avctx, int16_t *samples, int *frame_size_ptr, AVPacket *avpkt) { return ::avcodec_decode_audio2(avctx, samples, frame_size_ptr, avpkt->data, avpkt->size); }
virtual int avcodec_decode_subtitle2(AVCodecContext *avctx, AVSubtitle *sub, int *got_sub_ptr, AVPacket *avpkt) { return ::avcodec_decode_subtitle(avctx, sub, got_sub_ptr, avpkt->data, avpkt->size); }
#endif
virtual int avcodec_encode_audio(AVCodecContext *avctx, uint8_t *buf, int buf_size, const short *samples) { return ::avcodec_encode_audio(avctx, buf, buf_size, samples); }
virtual int avpicture_get_size(PixelFormat pix_fmt, int width, int height) { return ::avpicture_get_size(pix_fmt, width, height); }
virtual AVCodecContext *avcodec_alloc_context() { return ::avcodec_alloc_context(); }
virtual void avcodec_string(char *buf, int buf_size, AVCodecContext *enc, int encode) { ::avcodec_string(buf, buf_size, enc, encode); }
virtual void avcodec_get_context_defaults(AVCodecContext *s) { ::avcodec_get_context_defaults(s); }
virtual AVCodecParserContext *av_parser_init(int codec_id) { return ::av_parser_init(codec_id); }
virtual int av_parser_parse2(AVCodecParserContext *s,AVCodecContext *avctx, uint8_t **poutbuf, int *poutbuf_size,
const uint8_t *buf, int buf_size,
int64_t pts, int64_t dts, int64_t pos)
{
#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(52,21,0)
// API added on : 2009-03-05
return ::av_parser_parse2(s, avctx, poutbuf, poutbuf_size, buf, buf_size, pts, dts, pos);
#else
return ::av_parser_parse(s, avctx, poutbuf, poutbuf_size, buf, buf_size, pts, dts);
#endif
}
virtual void av_parser_close(AVCodecParserContext *s) { ::av_parser_close(s); }
virtual AVBitStreamFilterContext *av_bitstream_filter_init(const char *name) { return ::av_bitstream_filter_init(name); }
virtual int av_bitstream_filter_filter(AVBitStreamFilterContext *bsfc,
AVCodecContext *avctx, const char *args,
uint8_t **poutbuf, int *poutbuf_size,
const uint8_t *buf, int buf_size, int keyframe) { return ::av_bitstream_filter_filter(bsfc, avctx, args, poutbuf, poutbuf_size, buf, buf_size, keyframe); }
virtual void av_bitstream_filter_close(AVBitStreamFilterContext *bsfc) { ::av_bitstream_filter_close(bsfc); }
virtual void avpicture_free(AVPicture *picture) { ::avpicture_free(picture); }
virtual void av_free_packet(AVPacket *pkt) { ::av_free_packet(pkt); }
virtual int avpicture_alloc(AVPicture *picture, PixelFormat pix_fmt, int width, int height) { return ::avpicture_alloc(picture, pix_fmt, width, height); }
virtual int avcodec_default_get_buffer(AVCodecContext *s, AVFrame *pic) { return ::avcodec_default_get_buffer(s, pic); }
virtual void avcodec_default_release_buffer(AVCodecContext *s, AVFrame *pic) { ::avcodec_default_release_buffer(s, pic); }
virtual enum PixelFormat avcodec_default_get_format(struct AVCodecContext *s, const enum PixelFormat *fmt) { return ::avcodec_default_get_format(s, fmt); }
virtual int avcodec_thread_init(AVCodecContext *s, int thread_count) { return ::avcodec_thread_init(s, thread_count); }
virtual AVCodec *av_codec_next(AVCodec *c) { return ::av_codec_next(c); }
virtual AVAudioConvert *av_audio_convert_alloc(enum AVSampleFormat out_fmt, int out_channels,
enum AVSampleFormat in_fmt , int in_channels,
const float *matrix , int flags)
{ return ::av_audio_convert_alloc(out_fmt, out_channels, in_fmt, in_channels, matrix, flags); }
virtual void av_audio_convert_free(AVAudioConvert *ctx)
{ ::av_audio_convert_free(ctx); }
virtual int av_audio_convert(AVAudioConvert *ctx,
void * const out[6], const int out_stride[6],
const void * const in[6], const int in_stride[6], int len)
{ return ::av_audio_convert(ctx, out, out_stride, in, in_stride, len); }
virtual int av_dup_packet(AVPacket *pkt) { return ::av_dup_packet(pkt); }
virtual void av_init_packet(AVPacket *pkt) { return ::av_init_packet(pkt); }
virtual int64_t avcodec_guess_channel_layout(int nb_channels, enum CodecID codec_id, const char *fmt_name) { return ::avcodec_guess_channel_layout(nb_channels, codec_id, fmt_name); }
// DLL faking.
virtual bool ResolveExports() { return true; }
virtual bool Load() {
CLog::Log(LOGDEBUG, "DllAvCodec: Using libavcodec system library");
return true;
}
virtual void Unload() {}
};
#else
class DllAvCodec : public DllDynamic, DllAvCodecInterface
{
DECLARE_DLL_WRAPPER(DllAvCodec, DLL_PATH_LIBAVCODEC)
#ifndef _LINUX
DEFINE_FUNC_ALIGNED1(void, __cdecl, avcodec_flush_buffers, AVCodecContext*)
DEFINE_FUNC_ALIGNED2(int, __cdecl, avcodec_open_dont_call, AVCodecContext*, AVCodec *)
DEFINE_FUNC_ALIGNED4(int, __cdecl, avcodec_decode_video2, AVCodecContext*, AVFrame*, int*, AVPacket*)
DEFINE_FUNC_ALIGNED4(int, __cdecl, avcodec_decode_audio3, AVCodecContext*, int16_t*, int*, AVPacket*)
DEFINE_FUNC_ALIGNED4(int, __cdecl, avcodec_decode_subtitle2, AVCodecContext*, AVSubtitle*, int*, AVPacket*)
DEFINE_FUNC_ALIGNED4(int, __cdecl, avcodec_encode_audio, AVCodecContext*, uint8_t*, int, const short*)
DEFINE_FUNC_ALIGNED0(AVCodecContext*, __cdecl, avcodec_alloc_context)
DEFINE_FUNC_ALIGNED1(AVCodecParserContext*, __cdecl, av_parser_init, int)
DEFINE_FUNC_ALIGNED9(int, __cdecl, av_parser_parse2, AVCodecParserContext*,AVCodecContext*, uint8_t**, int*, const uint8_t*, int, int64_t, int64_t, int64_t)
#else
DEFINE_METHOD1(void, avcodec_flush_buffers, (AVCodecContext* p1))
DEFINE_METHOD2(int, avcodec_open_dont_call, (AVCodecContext* p1, AVCodec *p2))
DEFINE_METHOD4(int, avcodec_decode_video2, (AVCodecContext* p1, AVFrame *p2, int *p3, AVPacket *p4))
DEFINE_METHOD4(int, avcodec_decode_audio3, (AVCodecContext* p1, int16_t *p2, int *p3, AVPacket *p4))
DEFINE_METHOD4(int, avcodec_decode_subtitle2, (AVCodecContext* p1, AVSubtitle *p2, int *p3, AVPacket *p4))
DEFINE_METHOD4(int, avcodec_encode_audio, (AVCodecContext* p1, uint8_t *p2, int p3, const short *p4))
DEFINE_METHOD0(AVCodecContext*, avcodec_alloc_context)
DEFINE_METHOD1(AVCodecParserContext*, av_parser_init, (int p1))
DEFINE_METHOD9(int, av_parser_parse2, (AVCodecParserContext* p1, AVCodecContext* p2, uint8_t** p3, int* p4, const uint8_t* p5, int p6, int64_t p7, int64_t p8, int64_t p9))
#endif
DEFINE_METHOD1(int, av_dup_packet, (AVPacket *p1))
DEFINE_METHOD1(void, av_init_packet, (AVPacket *p1))
DEFINE_METHOD3(int64_t, avcodec_guess_channel_layout, (int p1, enum CodecID p2, const char *p3))
LOAD_SYMBOLS();
DEFINE_METHOD0(void, avcodec_register_all_dont_call)
DEFINE_METHOD1(AVCodec*, avcodec_find_decoder, (enum CodecID p1))
DEFINE_METHOD1(AVCodec*, avcodec_find_encoder, (enum CodecID p1))
DEFINE_METHOD1(int, avcodec_close_dont_call, (AVCodecContext *p1))
DEFINE_METHOD0(AVFrame*, avcodec_alloc_frame)
DEFINE_METHOD5(int, avpicture_fill, (AVPicture *p1, uint8_t *p2, PixelFormat p3, int p4, int p5))
DEFINE_METHOD3(int, avpicture_get_size, (PixelFormat p1, int p2, int p3))
DEFINE_METHOD4(void, avcodec_string, (char *p1, int p2, AVCodecContext *p3, int p4))
DEFINE_METHOD1(void, avcodec_get_context_defaults, (AVCodecContext *p1))
DEFINE_METHOD1(void, av_parser_close, (AVCodecParserContext *p1))
DEFINE_METHOD1(void, avpicture_free, (AVPicture *p1))
DEFINE_METHOD1(AVBitStreamFilterContext*, av_bitstream_filter_init, (const char *p1))
DEFINE_METHOD8(int, av_bitstream_filter_filter, (AVBitStreamFilterContext* p1, AVCodecContext* p2, const char* p3, uint8_t** p4, int* p5, const uint8_t* p6, int p7, int p8))
DEFINE_METHOD1(void, av_bitstream_filter_close, (AVBitStreamFilterContext *p1))
DEFINE_METHOD1(void, av_free_packet, (AVPacket *p1))
DEFINE_METHOD4(int, avpicture_alloc, (AVPicture *p1, PixelFormat p2, int p3, int p4))
DEFINE_METHOD2(int, avcodec_default_get_buffer, (AVCodecContext *p1, AVFrame *p2))
DEFINE_METHOD2(void, avcodec_default_release_buffer, (AVCodecContext *p1, AVFrame *p2))
DEFINE_METHOD2(enum PixelFormat, avcodec_default_get_format, (struct AVCodecContext *p1, const enum PixelFormat *p2))
DEFINE_METHOD2(int, avcodec_thread_init, (AVCodecContext *p1, int p2))
DEFINE_METHOD1(AVCodec*, av_codec_next, (AVCodec *p1))
DEFINE_METHOD6(AVAudioConvert*, av_audio_convert_alloc, (enum AVSampleFormat p1, int p2,
enum AVSampleFormat p3, int p4,
const float *p5, int p6))
DEFINE_METHOD1(void, av_audio_convert_free, (AVAudioConvert *p1));
DEFINE_METHOD6(int, av_audio_convert, (AVAudioConvert *p1,
void * const p2[6], const int p3[6],
const void * const p4[6], const int p5[6], int p6))
BEGIN_METHOD_RESOLVE()
RESOLVE_METHOD(avcodec_flush_buffers)
RESOLVE_METHOD_RENAME(avcodec_open,avcodec_open_dont_call)
RESOLVE_METHOD_RENAME(avcodec_close,avcodec_close_dont_call)
RESOLVE_METHOD(avcodec_find_decoder)
RESOLVE_METHOD(avcodec_find_encoder)
RESOLVE_METHOD(avcodec_alloc_frame)
RESOLVE_METHOD_RENAME(avcodec_register_all, avcodec_register_all_dont_call)
RESOLVE_METHOD(avpicture_fill)
RESOLVE_METHOD(avcodec_decode_video2)
RESOLVE_METHOD(avcodec_decode_audio3)
RESOLVE_METHOD(avcodec_decode_subtitle2)
RESOLVE_METHOD(avcodec_encode_audio)
RESOLVE_METHOD(avpicture_get_size)
RESOLVE_METHOD(avcodec_alloc_context)
RESOLVE_METHOD(avcodec_string)
RESOLVE_METHOD(avcodec_get_context_defaults)
RESOLVE_METHOD(av_parser_init)
RESOLVE_METHOD(av_parser_parse2)
RESOLVE_METHOD(av_parser_close)
RESOLVE_METHOD(av_bitstream_filter_init)
RESOLVE_METHOD(av_bitstream_filter_filter)
RESOLVE_METHOD(av_bitstream_filter_close)
RESOLVE_METHOD(avpicture_free)
RESOLVE_METHOD(avpicture_alloc)
RESOLVE_METHOD(av_free_packet)
RESOLVE_METHOD(avcodec_default_get_buffer)
RESOLVE_METHOD(avcodec_default_release_buffer)
RESOLVE_METHOD(avcodec_default_get_format)
RESOLVE_METHOD(avcodec_thread_init)
RESOLVE_METHOD(av_codec_next)
RESOLVE_METHOD(av_audio_convert_alloc)
RESOLVE_METHOD(av_audio_convert_free)
RESOLVE_METHOD(av_audio_convert)
RESOLVE_METHOD(av_dup_packet)
RESOLVE_METHOD(av_init_packet)
RESOLVE_METHOD(avcodec_guess_channel_layout)
END_METHOD_RESOLVE()
/* dependencies of libavcodec */
DllAvCore m_dllAvCore;
// DllAvUtil loaded implicitely by m_dllAvCore
public:
int avcodec_open(AVCodecContext *avctx, AVCodec *codec)
{
return avcodec_open_dont_call(avctx,codec);
}
int avcodec_close(AVCodecContext *avctx)
{
return avcodec_close_dont_call(avctx);
}
void avcodec_register_all()
{
avcodec_register_all_dont_call();
}
virtual bool Load()
{
if (!m_dllAvCore.Load())
return false;
return DllDynamic::Load();
}
};
#endif

186
DllAvCore.h Normal file
View file

@ -0,0 +1,186 @@
#pragma once
/*
* Copyright (C) 2005-2010 Team XBMC
* http://www.xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with XBMC; see the file COPYING. If not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#if (defined HAVE_CONFIG_H) && (!defined WIN32)
#include "config.h"
#endif
#include "DynamicDll.h"
#include "DllAvUtil.h"
#include "utils/log.h"
#ifndef AV_NOWARN_DEPRECATED
#define AV_NOWARN_DEPRECATED
#endif
extern "C" {
#ifdef USE_EXTERNAL_FFMPEG
#ifdef HAVE_LIBAVUTIL_SAMPLEFMT_H
// libavcore was merged to libavutil on 2010-02-15
#include <libavutil/audioconvert.h>
#include <libavutil/samplefmt.h>
#endif
#ifdef HAVE_LIBAVCORE_AVCORE_H
#include <libavcore/avcore.h>
#endif
#ifdef HAVE_LIBAVCORE_SAMPLEFMT_H
#include <libavcore/samplefmt.h>
#endif
/* Needed for old FFmpeg versions as used below */
#ifdef HAVE_LIBAVCODEC_AVCODEC_H
#include <libavcodec/avcodec.h>
#else
#include <ffmpeg/avcodec.h>
#endif
#else
#include "libavcore/avcore.h"
#include "libavcore/samplefmt.h"
#endif
}
/* Compatibility for old external FFmpeg versions. */
#ifdef USE_EXTERNAL_FFMPEG
#ifndef LIBAVCORE_VERSION_INT
// API added on: 2010-07-21, removed on 2010-02-15
#define LIBAVCORE_VERSION_INT 0
#endif
#ifndef AV_SAMPLE_FMT_NONE
// API added on: 2010-11-02
#define AVSampleFormat SampleFormat
#define AV_SAMPLE_FMT_NONE SAMPLE_FMT_NONE
#define AV_SAMPLE_FMT_U8 SAMPLE_FMT_U8
#define AV_SAMPLE_FMT_S16 SAMPLE_FMT_S16
#define AV_SAMPLE_FMT_S32 SAMPLE_FMT_S32
#define AV_SAMPLE_FMT_FLT SAMPLE_FMT_FLT
#define AV_SAMPLE_FMT_DBL SAMPLE_FMT_DBL
#endif
#ifndef AV_CH_FRONT_LEFT
// API added on: 2010-11-21
#define AV_CH_FRONT_LEFT CH_FRONT_LEFT
#define AV_CH_FRONT_RIGHT CH_FRONT_RIGHT
#define AV_CH_FRONT_CENTER CH_FRONT_CENTER
#define AV_CH_LOW_FREQUENCY CH_LOW_FREQUENCY
#define AV_CH_BACK_LEFT CH_BACK_LEFT
#define AV_CH_BACK_RIGHT CH_BACK_RIGHT
#define AV_CH_FRONT_LEFT_OF_CENTER CH_FRONT_LEFT_OF_CENTER
#define AV_CH_FRONT_RIGHT_OF_CENTER CH_FRONT_RIGHT_OF_CENTER
#define AV_CH_BACK_CENTER CH_BACK_CENTER
#define AV_CH_SIDE_LEFT CH_SIDE_LEFT
#define AV_CH_SIDE_RIGHT CH_SIDE_RIGHT
#define AV_CH_TOP_CENTER CH_TOP_CENTER
#define AV_CH_TOP_FRONT_LEFT CH_TOP_FRONT_LEFT
#define AV_CH_TOP_FRONT_CENTER CH_TOP_FRONT_CENTER
#define AV_CH_TOP_FRONT_RIGHT CH_TOP_FRONT_RIGHT
#define AV_CH_TOP_BACK_LEFT CH_TOP_BACK_LEFT
#define AV_CH_TOP_BACK_CENTER CH_TOP_BACK_CENTER
#define AV_CH_TOP_BACK_RIGHT CH_TOP_BACK_RIGHT
#define AV_CH_STEREO_LEFT CH_STEREO_LEFT
#define AV_CH_STEREO_RIGHT CH_STEREO_RIGHT
#define AV_CH_LAYOUT_NATIVE CH_LAYOUT_NATIVE
#define AV_CH_LAYOUT_MONO CH_LAYOUT_MONO
#define AV_CH_LAYOUT_STEREO CH_LAYOUT_STEREO
#define AV_CH_LAYOUT_2_1 CH_LAYOUT_2_1
#define AV_CH_LAYOUT_SURROUND CH_LAYOUT_SURROUND
#define AV_CH_LAYOUT_4POINT0 CH_LAYOUT_4POINT0
#define AV_CH_LAYOUT_2_2 CH_LAYOUT_2_2
#define AV_CH_LAYOUT_QUAD CH_LAYOUT_QUAD
#define AV_CH_LAYOUT_5POINT0 CH_LAYOUT_5POINT0
#define AV_CH_LAYOUT_5POINT1 CH_LAYOUT_5POINT1
#define AV_CH_LAYOUT_5POINT0_BACK CH_LAYOUT_5POINT0_BACK
#define AV_CH_LAYOUT_5POINT1_BACK CH_LAYOUT_5POINT1_BACK
#define AV_CH_LAYOUT_7POINT0 CH_LAYOUT_7POINT0
#define AV_CH_LAYOUT_7POINT1 CH_LAYOUT_7POINT1
#define AV_CH_LAYOUT_7POINT1_WIDE CH_LAYOUT_7POINT1_WIDE
#define AV_CH_LAYOUT_STEREO_DOWNMIX CH_LAYOUT_STEREO_DOWNMIX
#endif
#endif // USE_EXTERNAL_FFMPEG
class DllAvCoreInterface
{
public:
virtual ~DllAvCoreInterface() {}
virtual int av_get_bits_per_sample_fmt(enum AVSampleFormat sample_fmt) = 0;
};
#if (defined USE_EXTERNAL_FFMPEG)
// Use direct layer
class DllAvCore : public DllDynamic, DllAvCoreInterface
{
public:
virtual ~DllAvCore() {}
#if LIBAVCORE_VERSION_INT >= AV_VERSION_INT(0,12,0) || LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(50,38,0)
// API added on: 2010-11-02, moved to libavutil on 2010-02-15
virtual int av_get_bits_per_sample_fmt(enum AVSampleFormat sample_fmt) { return ::av_get_bits_per_sample_fmt(sample_fmt); }
#else
// from avcodec.h
virtual int av_get_bits_per_sample_fmt(enum AVSampleFormat sample_fmt) { return ::av_get_bits_per_sample_format(sample_fmt); }
#endif
// DLL faking.
virtual bool ResolveExports() { return true; }
virtual bool Load() {
#if LIBAVCORE_VERSION_INT > 0
CLog::Log(LOGDEBUG, "DllAvCore: Using libavcore system library");
#endif
return true;
}
virtual void Unload() {}
};
#else
class DllAvCore : public DllDynamic, DllAvCoreInterface
{
DECLARE_DLL_WRAPPER(DllAvCore, DLL_PATH_LIBAVCORE)
LOAD_SYMBOLS()
DEFINE_METHOD1(int, av_get_bits_per_sample_fmt, (enum AVSampleFormat p1))
BEGIN_METHOD_RESOLVE()
RESOLVE_METHOD(av_get_bits_per_sample_fmt)
END_METHOD_RESOLVE()
/* dependency of libavcore */
DllAvUtil m_dllAvUtil;
public:
virtual bool Load()
{
if (!m_dllAvUtil.Load())
return false;
return DllDynamic::Load();
}
};
#endif

331
DllAvFilter.h Normal file
View file

@ -0,0 +1,331 @@
#pragma once
/*
* Copyright (C) 2005-2011 Team XBMC
* http://www.xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with XBMC; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#if (defined HAVE_CONFIG_H) && (!defined WIN32)
#include "config.h"
#endif
#include "DynamicDll.h"
#include "DllAvCore.h"
#include "DllAvCodec.h"
#include "utils/log.h"
#ifndef AV_NOWARN_DEPRECATED
#define AV_NOWARN_DEPRECATED
#endif
extern "C" {
#ifndef HAVE_MMX
#define HAVE_MMX
#endif
#ifndef __STDC_CONSTANT_MACROS
#define __STDC_CONSTANT_MACROS
#endif
#ifndef __GNUC__
#pragma warning(disable:4244)
#endif
#if (defined USE_EXTERNAL_FFMPEG)
#if (defined HAVE_LIBAVFILTER_AVFILTER_H)
#include <libavfilter/avfiltergraph.h>
#elif (defined HAVE_FFMPEG_AVFILTER_H)
#include <ffmpeg/avfiltergraph.h>
#endif
/* for av_vsrc_buffer_add_frame */
#if LIBAVFILTER_VERSION_INT >= AV_VERSION_INT(2,8,0)
#include <libavfilter/avcodec.h>
#elif LIBAVFILTER_VERSION_INT >= AV_VERSION_INT(2,7,0)
int av_vsrc_buffer_add_frame(AVFilterContext *buffer_filter,
AVFrame *frame);
#elif LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(53,3,0)
int av_vsrc_buffer_add_frame(AVFilterContext *buffer_filter,
AVFrame *frame, int64_t pts);
#else
int av_vsrc_buffer_add_frame(AVFilterContext *buffer_filter,
AVFrame *frame, int64_t pts, AVRational pixel_aspect);
#endif
#else
#include "libavfilter/avfiltergraph.h"
#endif
}
//#include "threads/SingleLock.h"
class DllAvFilterInterface
{
public:
virtual ~DllAvFilterInterface() {}
virtual int avfilter_open(AVFilterContext **filter_ctx, AVFilter *filter, const char *inst_name)=0;
virtual void avfilter_free(AVFilterContext *filter)=0;
virtual void avfilter_graph_free(AVFilterGraph **graph)=0;
virtual int avfilter_graph_create_filter(AVFilterContext **filt_ctx, AVFilter *filt, const char *name, const char *args, void *opaque, AVFilterGraph *graph_ctx)=0;
virtual AVFilter *avfilter_get_by_name(const char *name)=0;
virtual AVFilterGraph *avfilter_graph_alloc(void)=0;
virtual AVFilterInOut *avfilter_inout_alloc()=0;
virtual void avfilter_inout_free(AVFilterInOut **inout)=0;
virtual int avfilter_graph_parse(AVFilterGraph *graph, const char *filters, AVFilterInOut **inputs, AVFilterInOut **outputs, void *log_ctx)=0;
virtual int avfilter_graph_config(AVFilterGraph *graphctx, void *log_ctx)=0;
virtual int avfilter_poll_frame(AVFilterLink *link)=0;
virtual int avfilter_request_frame(AVFilterLink *link)=0;
#if LIBAVFILTER_VERSION_INT >= AV_VERSION_INT(2,13,0)
virtual int av_vsrc_buffer_add_frame(AVFilterContext *buffer_filter, AVFrame *frame, int flags)=0;
#elif LIBAVFILTER_VERSION_INT >= AV_VERSION_INT(2,7,0)
virtual int av_vsrc_buffer_add_frame(AVFilterContext *buffer_filter, AVFrame *frame)=0;
#elif LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(53,3,0)
virtual int av_vsrc_buffer_add_frame(AVFilterContext *buffer_filter, AVFrame *frame, int64_t pts)=0;
#else
virtual int av_vsrc_buffer_add_frame(AVFilterContext *buffer_filter, AVFrame *frame, int64_t pts, AVRational pixel_aspect)=0;
#endif
virtual AVFilterBufferRef *avfilter_get_video_buffer(AVFilterLink *link, int perms, int w, int h)=0;
virtual void avfilter_unref_buffer(AVFilterBufferRef *ref)=0;
virtual int avfilter_link(AVFilterContext *src, unsigned srcpad, AVFilterContext *dst, unsigned dstpad)=0;
};
#if (defined USE_EXTERNAL_FFMPEG)
// Use direct mapping
class DllAvFilter : public DllDynamic, DllAvFilterInterface
{
public:
virtual ~DllAvFilter() {}
virtual int avfilter_open(AVFilterContext **filter_ctx, AVFilter *filter, const char *inst_name)
{
return ::avfilter_open(filter_ctx, filter, inst_name);
}
virtual void avfilter_free(AVFilterContext *filter)
{
::avfilter_free(filter);
}
virtual void avfilter_graph_free(AVFilterGraph **graph)
{
#if LIBAVFILTER_VERSION_INT >= AV_VERSION_INT(1,76,0)
::avfilter_graph_free(graph);
#else
::avfilter_graph_free(*graph);
*graph = NULL;
#endif
}
void avfilter_register_all()
{
::avfilter_register_all();
}
virtual int avfilter_graph_create_filter(AVFilterContext **filt_ctx, AVFilter *filt, const char *name, const char *args, void *opaque, AVFilterGraph *graph_ctx) { return ::avfilter_graph_create_filter(filt_ctx, filt, name, args, opaque, graph_ctx); }
virtual AVFilter *avfilter_get_by_name(const char *name) { return ::avfilter_get_by_name(name); }
virtual AVFilterGraph *avfilter_graph_alloc() { return ::avfilter_graph_alloc(); }
virtual AVFilterInOut *avfilter_inout_alloc()
{
#if LIBAVFILTER_VERSION_INT >= AV_VERSION_INT(2,17,0)
return ::avfilter_inout_alloc();
#else
return (AVFilterInOut*)::av_mallocz(sizeof(AVFilterInOut));
#endif
}
virtual void avfilter_inout_free(AVFilterInOut **inout)
{
#if LIBAVFILTER_VERSION_INT >= AV_VERSION_INT(2,17,0)
::avfilter_inout_free(inout);
#else
*inout = NULL;
#endif
}
virtual int avfilter_graph_parse(AVFilterGraph *graph, const char *filters, AVFilterInOut **inputs, AVFilterInOut **outputs, void *log_ctx)
{
#if LIBAVFILTER_VERSION_INT >= AV_VERSION_INT(2,16,0)
return ::avfilter_graph_parse(graph, filters, inputs, outputs, log_ctx);
#elif LIBAVFILTER_VERSION_INT >= AV_VERSION_INT(2,15,1)
return ::avfilter_graph_parse(graph, filters, *inputs, *outputs, log_ctx);
#else
return ::avfilter_graph_parse(graph, filters, *inputs, *outputs, (AVClass*)log_ctx);
#endif
}
virtual int avfilter_graph_config(AVFilterGraph *graphctx, void *log_ctx)
{
#if LIBAVFILTER_VERSION_INT >= AV_VERSION_INT(2,15,1)
return ::avfilter_graph_config(graphctx, log_ctx);
#else
return ::avfilter_graph_config(graphctx, (AVClass*)log_ctx);
#endif
}
virtual int avfilter_poll_frame(AVFilterLink *link) { return ::avfilter_poll_frame(link); }
virtual int avfilter_request_frame(AVFilterLink *link) { return ::avfilter_request_frame(link); }
#if LIBAVFILTER_VERSION_INT >= AV_VERSION_INT(2,13,0)
virtual int av_vsrc_buffer_add_frame(AVFilterContext *buffer_filter, AVFrame *frame, int flags) { return ::av_vsrc_buffer_add_frame(buffer_filter, frame, flags); }
#elif LIBAVFILTER_VERSION_INT >= AV_VERSION_INT(2,7,0)
virtual int av_vsrc_buffer_add_frame(AVFilterContext *buffer_filter, AVFrame *frame) { return ::av_vsrc_buffer_add_frame(buffer_filter, frame); }
#elif LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(53,3,0)
virtual int av_vsrc_buffer_add_frame(AVFilterContext *buffer_filter, AVFrame *frame, int64_t pts) { return ::av_vsrc_buffer_add_frame(buffer_filter, frame, pts); }
#else
virtual int av_vsrc_buffer_add_frame(AVFilterContext *buffer_filter, AVFrame *frame, int64_t pts, AVRational pixel_aspect) { return ::av_vsrc_buffer_add_frame(buffer_filter, frame, pts, pixel_aspect); }
#endif
virtual AVFilterBufferRef *avfilter_get_video_buffer(AVFilterLink *link, int perms, int w, int h) { return ::avfilter_get_video_buffer(link, perms, w, h); }
virtual void avfilter_unref_buffer(AVFilterBufferRef *ref) { ::avfilter_unref_buffer(ref); }
virtual int avfilter_link(AVFilterContext *src, unsigned srcpad, AVFilterContext *dst, unsigned dstpad) { return ::avfilter_link(src, srcpad, dst, dstpad); }
// DLL faking.
virtual bool ResolveExports() { return true; }
virtual bool Load() {
CLog::Log(LOGDEBUG, "DllAvFilter: Using libavfilter system library");
return true;
}
virtual void Unload() {}
};
#else
class DllAvFilter : public DllDynamic, DllAvFilterInterface
{
DECLARE_DLL_WRAPPER(DllAvFilter, DLL_PATH_LIBAVFILTER)
LOAD_SYMBOLS()
DEFINE_METHOD3(int, avfilter_open_dont_call, (AVFilterContext **p1, AVFilter *p2, const char *p3))
DEFINE_METHOD1(void, avfilter_free_dont_call, (AVFilterContext *p1))
#if LIBAVFILTER_VERSION_INT >= AV_VERSION_INT(1,76,0)
DEFINE_METHOD1(void, avfilter_graph_free_dont_call, (AVFilterGraph **p1))
#else
DEFINE_METHOD1(void, avfilter_graph_free_dont_call, (AVFilterGraph *p1))
#endif
DEFINE_METHOD0(void, avfilter_register_all_dont_call)
DEFINE_METHOD6(int, avfilter_graph_create_filter, (AVFilterContext **p1, AVFilter *p2, const char *p3, const char *p4, void *p5, AVFilterGraph *p6))
DEFINE_METHOD1(AVFilter*, avfilter_get_by_name, (const char *p1))
DEFINE_METHOD0(AVFilterGraph*, avfilter_graph_alloc)
#if LIBAVFILTER_VERSION_INT >= AV_VERSION_INT(2,17,0)
DEFINE_METHOD0(AVFilterInOut*, avfilter_inout_alloc_dont_call)
DEFINE_METHOD1(void, avfilter_inout_free_dont_call, (AVFilterInOut **p1))
#endif
#if LIBAVFILTER_VERSION_INT >= AV_VERSION_INT(2,16,0)
DEFINE_METHOD5(int, avfilter_graph_parse_dont_call, (AVFilterGraph *p1, const char *p2, AVFilterInOut **p3, AVFilterInOut **p4, void *p5))
#elif LIBAVFILTER_VERSION_INT >= AV_VERSION_INT(2,15,1)
DEFINE_METHOD5(int, avfilter_graph_parse_dont_call, (AVFilterGraph *p1, const char *p2, AVFilterInOut *p3, AVFilterInOut *p4, void *p5))
#else
DEFINE_METHOD5(int, avfilter_graph_parse_dont_call, (AVFilterGraph *p1, const char *p2, AVFilterInOut *p3, AVFilterInOut *p4, AVClass *p5))
#endif
#if LIBAVFILTER_VERSION_INT >= AV_VERSION_INT(2,15,1)
DEFINE_METHOD2(int, avfilter_graph_config_dont_call, (AVFilterGraph *p1, void *p2))
#else
DEFINE_METHOD2(int, avfilter_graph_config_dont_call, (AVFilterGraph *p1, AVClass *p2))
#endif
#ifdef _LINUX
DEFINE_METHOD1(int, avfilter_poll_frame, (AVFilterLink *p1))
DEFINE_METHOD1(int, avfilter_request_frame, (AVFilterLink* p1))
#else
DEFINE_FUNC_ALIGNED1(int, __cdecl, avfilter_poll_frame, AVFilterLink *)
DEFINE_FUNC_ALIGNED1(int, __cdecl, avfilter_request_frame, AVFilterLink*)
#endif
#if LIBAVFILTER_VERSION_INT >= AV_VERSION_INT(2,13,0)
DEFINE_METHOD3(int, av_vsrc_buffer_add_frame, (AVFilterContext *p1, AVFrame *p2, int p3))
#elif LIBAVFILTER_VERSION_INT >= AV_VERSION_INT(2,7,0)
DEFINE_METHOD2(int, av_vsrc_buffer_add_frame, (AVFilterContext *p1, AVFrame *p2))
#elif LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(53,3,0)
DEFINE_METHOD3(int, av_vsrc_buffer_add_frame, (AVFilterContext *p1, AVFrame *p2, int64_t p3))
#else
DEFINE_METHOD4(int, av_vsrc_buffer_add_frame, (AVFilterContext *p1, AVFrame *p2, int64_t p3, AVRational p4))
#endif
DEFINE_METHOD4(AVFilterBufferRef*, avfilter_get_video_buffer, (AVFilterLink *p1, int p2, int p3, int p4))
DEFINE_METHOD1(void, avfilter_unref_buffer, (AVFilterBufferRef *p1))
DEFINE_METHOD4(int, avfilter_link, (AVFilterContext *p1, unsigned p2, AVFilterContext *p3, unsigned p4))
BEGIN_METHOD_RESOLVE()
RESOLVE_METHOD_RENAME(avfilter_open, avfilter_open_dont_call)
RESOLVE_METHOD_RENAME(avfilter_free, avfilter_free_dont_call)
RESOLVE_METHOD_RENAME(avfilter_graph_free, avfilter_graph_free_dont_call)
RESOLVE_METHOD_RENAME(avfilter_register_all, avfilter_register_all_dont_call)
RESOLVE_METHOD(avfilter_graph_create_filter)
RESOLVE_METHOD(avfilter_get_by_name)
RESOLVE_METHOD(avfilter_graph_alloc)
#if LIBAVFILTER_VERSION_INT >= AV_VERSION_INT(2,17,0)
RESOLVE_METHOD_RENAME(avfilter_inout_alloc, avfilter_inout_alloc_dont_call)
RESOLVE_METHOD_RENAME(avfilter_inout_free, avfilter_inout_free_dont_call)
#endif
RESOLVE_METHOD_RENAME(avfilter_graph_parse, avfilter_graph_parse_dont_call)
RESOLVE_METHOD_RENAME(avfilter_graph_config, avfilter_graph_config_dont_call)
RESOLVE_METHOD(avfilter_poll_frame)
RESOLVE_METHOD(avfilter_request_frame)
RESOLVE_METHOD(av_vsrc_buffer_add_frame)
RESOLVE_METHOD(avfilter_get_video_buffer)
RESOLVE_METHOD(avfilter_unref_buffer)
RESOLVE_METHOD(avfilter_link)
END_METHOD_RESOLVE()
/* dependencies of libavfilter */
DllAvUtil m_dllAvUtil;
public:
int avfilter_open(AVFilterContext **filter_ctx, AVFilter *filter, const char *inst_name)
{
return avfilter_open_dont_call(filter_ctx, filter, inst_name);
}
void avfilter_free(AVFilterContext *filter)
{
avfilter_free_dont_call(filter);
}
void avfilter_graph_free(AVFilterGraph **graph)
{
#if LIBAVFILTER_VERSION_INT >= AV_VERSION_INT(1,76,0)
avfilter_graph_free_dont_call(graph);
#else
avfilter_graph_free_dont_call(*graph);
m_dllAvUtil.av_freep(graph);
#endif
}
void avfilter_register_all()
{
avfilter_register_all_dont_call();
}
AVFilterInOut* avfilter_inout_alloc()
{
#if LIBAVFILTER_VERSION_INT >= AV_VERSION_INT(2,17,0)
return avfilter_inout_alloc_dont_call();
#else
return (AVFilterInOut*)m_dllAvUtil.av_mallocz(sizeof(AVFilterInOut));
#endif
}
int avfilter_graph_parse(AVFilterGraph *graph, const char *filters, AVFilterInOut **inputs, AVFilterInOut **outputs, void *log_ctx)
{
#if LIBAVFILTER_VERSION_INT >= AV_VERSION_INT(2,16,0)
return avfilter_graph_parse_dont_call(graph, filters, inputs, outputs, log_ctx);
#elif LIBAVFILTER_VERSION_INT >= AV_VERSION_INT(2,15,1)
return avfilter_graph_parse_dont_call(graph, filters, *inputs, *outputs, log_ctx);
#else
return avfilter_graph_parse_dont_call(graph, filters, *inputs, *outputs, (AVClass*)log_ctx);
#endif
}
void avfilter_inout_free(AVFilterInOut **inout)
{
#if LIBAVFILTER_VERSION_INT >= AV_VERSION_INT(2,17,0)
avfilter_inout_free_dont_call(inout);
#else
*inout = NULL;
#endif
}
int avfilter_graph_config(AVFilterGraph *graphctx, void *log_ctx)
{
#if LIBAVFILTER_VERSION_INT >= AV_VERSION_INT(2,15,1)
return avfilter_graph_config_dont_call(graphctx, log_ctx);
#else
return avfilter_graph_config_dont_call(graphctx, (AVClass*)log_ctx);
#endif
}
virtual bool Load()
{
if (!m_dllAvUtil.Load())
return false;
return DllDynamic::Load();
}
};
#endif

333
DllAvFormat.h Normal file
View file

@ -0,0 +1,333 @@
#pragma once
/*
* Copyright (C) 2005-2010 Team XBMC
* http://www.xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with XBMC; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#if (defined HAVE_CONFIG_H) && (!defined WIN32)
#include "config.h"
#endif
#include "DynamicDll.h"
#include "DllAvCodec.h"
#ifndef AV_NOWARN_DEPRECATED
#define AV_NOWARN_DEPRECATED
#endif
extern "C" {
#ifndef HAVE_MMX
#define HAVE_MMX
#endif
#ifndef __STDC_CONSTANT_MACROS
#define __STDC_CONSTANT_MACROS
#endif
#ifndef __GNUC__
#pragma warning(disable:4244)
#endif
#if (defined USE_EXTERNAL_FFMPEG)
#if (defined HAVE_LIBAVFORMAT_AVFORMAT_H)
#include <libavformat/avformat.h>
#else
#include <ffmpeg/avformat.h>
#endif
/* libavformat/riff.h is not a public header, so include it here */
//#include "libavformat/riff.h"
#else
#include "libavformat/avformat.h"
//#include "libavformat/riff.h"
#endif
}
/* Flag introduced without a version bump */
#ifndef AVSEEK_FORCE
#define AVSEEK_FORCE 0x20000
#endif
typedef int64_t offset_t;
class DllAvFormatInterface
{
public:
virtual ~DllAvFormatInterface() {}
virtual void av_register_all_dont_call(void)=0;
virtual AVInputFormat *av_find_input_format(const char *short_name)=0;
virtual int url_feof(ByteIOContext *s)=0;
virtual AVMetadataTag *av_metadata_get(AVMetadata *m, const char *key, const AVMetadataTag *prev, int flags)=0;
virtual void av_close_input_file(AVFormatContext *s)=0;
virtual void av_close_input_stream(AVFormatContext *s)=0;
virtual int av_read_frame(AVFormatContext *s, AVPacket *pkt)=0;
virtual int av_read_play(AVFormatContext *s)=0;
virtual int av_read_pause(AVFormatContext *s)=0;
virtual int av_seek_frame(AVFormatContext *s, int stream_index, int64_t timestamp, int flags)=0;
#if (!defined USE_EXTERNAL_FFMPEG)
virtual int av_find_stream_info_dont_call(AVFormatContext *ic)=0;
#endif
virtual int av_open_input_file(AVFormatContext **ic_ptr, const char *filename, AVInputFormat *fmt, int buf_size, AVFormatParameters *ap)=0;
virtual void url_set_interrupt_cb(URLInterruptCB *interrupt_cb)=0;
virtual int av_open_input_stream(AVFormatContext **ic_ptr, ByteIOContext *pb, const char *filename, AVInputFormat *fmt, AVFormatParameters *ap)=0;
virtual AVInputFormat *av_probe_input_format(AVProbeData *pd, int is_opened)=0;
virtual AVInputFormat *av_probe_input_format2(AVProbeData *pd, int is_opened, int *score_max)=0;
virtual int av_probe_input_buffer(ByteIOContext *pb, AVInputFormat **fmt, const char *filename, void *logctx, unsigned int offset, unsigned int max_probe_size)=0;
virtual void dump_format(AVFormatContext *ic, int index, const char *url, int is_output)=0;
virtual int url_fdopen(ByteIOContext **s, URLContext *h)=0;
virtual int url_fopen(ByteIOContext **s, const char *filename, int flags)=0;
virtual int url_fclose(ByteIOContext *s)=0;
virtual int url_open_dyn_buf(ByteIOContext **s)=0;
virtual int url_close_dyn_buf(ByteIOContext *s, uint8_t **pbuffer)=0;
virtual offset_t url_fseek(ByteIOContext *s, offset_t offset, int whence)=0;
virtual int get_buffer(ByteIOContext *s, unsigned char *buf, int size)=0;
virtual int get_partial_buffer(ByteIOContext *s, unsigned char *buf, int size)=0;
virtual void put_byte(ByteIOContext *s, int b)=0;
virtual void put_buffer(ByteIOContext *s, const unsigned char *buf, int size)=0;
virtual void put_be24(ByteIOContext *s, unsigned int val)=0;
virtual void put_be32(ByteIOContext *s, unsigned int val)=0;
virtual void put_be16(ByteIOContext *s, unsigned int val)=0;
virtual AVFormatContext *avformat_alloc_context(void)=0;
virtual AVStream *av_new_stream(AVFormatContext *s, int id)=0;
virtual AVOutputFormat *av_guess_format(const char *short_name, const char *filename, const char *mime_type)=0;
virtual int av_set_parameters(AVFormatContext *s, AVFormatParameters *ap)=0;
virtual ByteIOContext *av_alloc_put_byte(unsigned char *buffer, int buffer_size, int write_flag, void *opaque,
int (*read_packet)(void *opaque, uint8_t *buf, int buf_size),
int (*write_packet)(void *opaque, uint8_t *buf, int buf_size),
offset_t (*seek)(void *opaque, offset_t offset, int whence))=0;
virtual int av_write_header (AVFormatContext *s)=0;
virtual int av_write_trailer(AVFormatContext *s)=0;
virtual int av_write_frame (AVFormatContext *s, AVPacket *pkt)=0;
virtual int av_metadata_set2(AVMetadata **pm, const char *key, const char *value, int flags)=0;
virtual int64_t av_gettime(void)=0;
};
#if (defined USE_EXTERNAL_FFMPEG)
// Use direct mapping
class DllAvFormat : public DllDynamic, DllAvFormatInterface
{
public:
virtual ~DllAvFormat() {}
virtual void av_register_all()
{
return ::av_register_all();
}
virtual void av_register_all_dont_call() { *(int* )0x0 = 0; }
virtual AVInputFormat *av_find_input_format(const char *short_name) { return ::av_find_input_format(short_name); }
virtual int url_feof(ByteIOContext *s) { return ::url_feof(s); }
#if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(52,31,0)
// API added on: 2009-03-01
virtual AVMetadataTag *av_metadata_get(AVMetadata *m, const char *key, const AVMetadataTag *prev, int flags){ return ::av_metadata_get(m, key, prev, flags); }
#else
virtual AVMetadataTag *av_metadata_get(AVMetadata *m, const char *key, const AVMetadataTag *prev, int flags){ return NULL; }
#endif
virtual void av_close_input_file(AVFormatContext *s) { ::av_close_input_file(s); }
virtual void av_close_input_stream(AVFormatContext *s) { ::av_close_input_stream(s); }
virtual int av_read_frame(AVFormatContext *s, AVPacket *pkt) { return ::av_read_frame(s, pkt); }
virtual int av_read_play(AVFormatContext *s) { return ::av_read_play(s); }
virtual int av_read_pause(AVFormatContext *s) { return ::av_read_pause(s); }
virtual int av_seek_frame(AVFormatContext *s, int stream_index, int64_t timestamp, int flags) { return ::av_seek_frame(s, stream_index, timestamp, flags); }
virtual int av_find_stream_info(AVFormatContext *ic)
{
return ::av_find_stream_info(ic);
}
virtual int av_open_input_file(AVFormatContext **ic_ptr, const char *filename, AVInputFormat *fmt, int buf_size, AVFormatParameters *ap) { return ::av_open_input_file(ic_ptr, filename, fmt, buf_size, ap); }
virtual void url_set_interrupt_cb(URLInterruptCB *interrupt_cb) { ::url_set_interrupt_cb(interrupt_cb); }
virtual int av_open_input_stream(AVFormatContext **ic_ptr, ByteIOContext *pb, const char *filename, AVInputFormat *fmt, AVFormatParameters *ap) { return ::av_open_input_stream(ic_ptr, pb, filename, fmt, ap); }
virtual AVInputFormat *av_probe_input_format(AVProbeData *pd, int is_opened) {return ::av_probe_input_format(pd, is_opened); }
virtual AVInputFormat *av_probe_input_format2(AVProbeData *pd, int is_opened, int *score_max) {*score_max = 100; return ::av_probe_input_format(pd, is_opened); } // Use av_probe_input_format, this is not exported by ffmpeg's headers
#if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(52,98,0)
// API added on: 2010-02-08
virtual int av_probe_input_buffer(ByteIOContext *pb, AVInputFormat **fmt, const char *filename, void *logctx, unsigned int offset, unsigned int max_probe_size) { return ::av_probe_input_buffer(pb, fmt, filename, logctx, offset, max_probe_size); }
#else
virtual int av_probe_input_buffer(ByteIOContext *pb, AVInputFormat **fmt, const char *filename, void *logctx, unsigned int offset, unsigned int max_probe_size) { return -1; }
#endif
virtual void dump_format(AVFormatContext *ic, int index, const char *url, int is_output) { ::dump_format(ic, index, url, is_output); }
virtual int url_fdopen(ByteIOContext **s, URLContext *h) { return ::url_fdopen(s, h); }
virtual int url_fopen(ByteIOContext **s, const char *filename, int flags) { return ::url_fopen(s, filename, flags); }
virtual int url_fclose(ByteIOContext *s) { return ::url_fclose(s); }
virtual int url_open_dyn_buf(ByteIOContext **s) { return ::url_open_dyn_buf(s); }
virtual int url_close_dyn_buf(ByteIOContext *s, uint8_t **pbuffer) { return ::url_close_dyn_buf(s, pbuffer); }
virtual offset_t url_fseek(ByteIOContext *s, offset_t offset, int whence) { return ::url_fseek(s, offset, whence); }
virtual int get_buffer(ByteIOContext *s, unsigned char *buf, int size) { return ::get_buffer(s, buf, size); }
virtual int get_partial_buffer(ByteIOContext *s, unsigned char *buf, int size) { return ::get_partial_buffer(s, buf, size); }
virtual void put_byte(ByteIOContext *s, int b) { ::put_byte(s, b); }
virtual void put_buffer(ByteIOContext *s, const unsigned char *buf, int size) { ::put_buffer(s, buf, size); }
virtual void put_be24(ByteIOContext *s, unsigned int val) { ::put_be24(s, val); }
virtual void put_be32(ByteIOContext *s, unsigned int val) { ::put_be32(s, val); }
virtual void put_be16(ByteIOContext *s, unsigned int val) { ::put_be16(s, val); }
virtual AVFormatContext *avformat_alloc_context() { return ::avformat_alloc_context(); }
virtual AVStream *av_new_stream(AVFormatContext *s, int id) { return ::av_new_stream(s, id); }
#if LIBAVFORMAT_VERSION_INT < (52<<16 | 45<<8)
virtual AVOutputFormat *av_guess_format(const char *short_name, const char *filename, const char *mime_type) { return ::guess_format(short_name, filename, mime_type); }
#else
virtual AVOutputFormat *av_guess_format(const char *short_name, const char *filename, const char *mime_type) { return ::av_guess_format(short_name, filename, mime_type); }
#endif
virtual int av_set_parameters(AVFormatContext *s, AVFormatParameters *ap) { return ::av_set_parameters(s, ap); }
virtual ByteIOContext *av_alloc_put_byte(unsigned char *buffer, int buffer_size, int write_flag, void *opaque,
int (*read_packet)(void *opaque, uint8_t *buf, int buf_size),
int (*write_packet)(void *opaque, uint8_t *buf, int buf_size),
offset_t (*seek)(void *opaque, offset_t offset, int whence)) { return ::av_alloc_put_byte(buffer, buffer_size, write_flag, opaque, read_packet, write_packet, seek); }
virtual int av_write_header (AVFormatContext *s) { return ::av_write_header (s); }
virtual int av_write_trailer(AVFormatContext *s) { return ::av_write_trailer(s); }
virtual int av_write_frame (AVFormatContext *s, AVPacket *pkt) { return ::av_write_frame(s, pkt); }
#if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(52,43,0)
// API added on: 2009-12-13
virtual int av_metadata_set2(AVMetadata **pm, const char *key, const char *value, int flags) { return ::av_metadata_set2(pm, key, value, flags); }
#elif LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(52,31,0)
// API added on: 2009-03-01
virtual int av_metadata_set2(AVMetadata **pm, const char *key, const char *value, int flags) { return ::av_metadata_set(pm, key, value); }
#else
virtual int av_metadata_set2(AVMetadata **pm, const char *key, const char *value, int flags) { return -1; }
#endif
virtual int64_t av_gettime(void) { return ::av_gettime(); }
// DLL faking.
virtual bool ResolveExports() { return true; }
virtual bool Load() {
CLog::Log(LOGDEBUG, "DllAvFormat: Using libavformat system library");
return true;
}
virtual void Unload() {}
};
#else
class DllAvFormat : public DllDynamic, DllAvFormatInterface
{
DECLARE_DLL_WRAPPER(DllAvFormat, DLL_PATH_LIBAVFORMAT)
LOAD_SYMBOLS()
DEFINE_METHOD0(void, av_register_all_dont_call)
DEFINE_METHOD1(AVInputFormat*, av_find_input_format, (const char *p1))
DEFINE_METHOD1(int, url_feof, (ByteIOContext *p1))
DEFINE_METHOD4(AVMetadataTag*, av_metadata_get, (AVMetadata *p1, const char *p2, const AVMetadataTag *p3, int p4))
DEFINE_METHOD1(void, av_close_input_file, (AVFormatContext *p1))
DEFINE_METHOD1(void, av_close_input_stream, (AVFormatContext *p1))
DEFINE_METHOD1(int, av_read_play, (AVFormatContext *p1))
DEFINE_METHOD1(int, av_read_pause, (AVFormatContext *p1))
DEFINE_FUNC_ALIGNED2(int, __cdecl, av_read_frame, AVFormatContext *, AVPacket *)
DEFINE_FUNC_ALIGNED4(int, __cdecl, av_seek_frame, AVFormatContext*, int, int64_t, int)
DEFINE_FUNC_ALIGNED1(int, __cdecl, av_find_stream_info_dont_call, AVFormatContext*)
DEFINE_FUNC_ALIGNED5(int, __cdecl, av_open_input_file, AVFormatContext**, const char *, AVInputFormat *, int, AVFormatParameters *)
DEFINE_FUNC_ALIGNED5(int,__cdecl, av_open_input_stream, AVFormatContext **, ByteIOContext *, const char *, AVInputFormat *, AVFormatParameters *)
DEFINE_FUNC_ALIGNED2(AVInputFormat*, __cdecl, av_probe_input_format, AVProbeData*, int)
DEFINE_FUNC_ALIGNED3(AVInputFormat*, __cdecl, av_probe_input_format2, AVProbeData*, int, int*)
DEFINE_FUNC_ALIGNED6(int, __cdecl, av_probe_input_buffer, ByteIOContext *, AVInputFormat **, const char *, void *, unsigned int, unsigned int)
DEFINE_FUNC_ALIGNED3(int, __cdecl, get_buffer, ByteIOContext*, unsigned char *, int)
DEFINE_FUNC_ALIGNED3(int, __cdecl, get_partial_buffer, ByteIOContext*, unsigned char *, int)
DEFINE_FUNC_ALIGNED2(void, __cdecl, put_byte, ByteIOContext*, int)
DEFINE_FUNC_ALIGNED3(void, __cdecl, put_buffer, ByteIOContext*, const unsigned char *, int)
DEFINE_FUNC_ALIGNED2(void, __cdecl, put_be24, ByteIOContext*, unsigned int)
DEFINE_FUNC_ALIGNED2(void, __cdecl, put_be32, ByteIOContext*, unsigned int)
DEFINE_FUNC_ALIGNED2(void, __cdecl, put_be16, ByteIOContext*, unsigned int)
DEFINE_METHOD1(void, url_set_interrupt_cb, (URLInterruptCB *p1))
DEFINE_METHOD4(void, dump_format, (AVFormatContext *p1, int p2, const char *p3, int p4))
DEFINE_METHOD2(int, url_fdopen, (ByteIOContext **p1, URLContext *p2))
DEFINE_METHOD3(int, url_fopen, (ByteIOContext **p1, const char *p2, int p3))
DEFINE_METHOD1(int, url_fclose, (ByteIOContext *p1))
DEFINE_METHOD1(int, url_open_dyn_buf, (ByteIOContext **p1))
DEFINE_METHOD2(int, url_close_dyn_buf, (ByteIOContext *p1, uint8_t **p2))
DEFINE_METHOD3(offset_t, url_fseek, (ByteIOContext *p1, offset_t p2, int p3))
DEFINE_METHOD0(AVFormatContext *, avformat_alloc_context)
DEFINE_METHOD2(AVStream *, av_new_stream, (AVFormatContext *p1, int p2))
#if LIBAVFORMAT_VERSION_INT < (52<<16 | 45<<8)
DEFINE_METHOD3(AVOutputFormat *, guess_format, (const char *p1, const char *p2, const char *p3))
#else
DEFINE_METHOD3(AVOutputFormat *, av_guess_format, (const char *p1, const char *p2, const char *p3))
#endif
DEFINE_METHOD2(int, av_set_parameters, (AVFormatContext *p1, AVFormatParameters *p2));
DEFINE_METHOD7(ByteIOContext *, av_alloc_put_byte, (unsigned char *p1, int p2, int p3, void *p4,
int(*p5)(void *opaque, uint8_t *buf, int buf_size),
int(*p6)(void *opaque, uint8_t *buf, int buf_size),
offset_t(*p7)(void *opaque, offset_t offset, int whence)))
DEFINE_METHOD1(int, av_write_header , (AVFormatContext *p1))
DEFINE_METHOD1(int, av_write_trailer, (AVFormatContext *p1))
DEFINE_METHOD2(int, av_write_frame , (AVFormatContext *p1, AVPacket *p2))
DEFINE_METHOD4(int, av_metadata_set2, (AVMetadata **p1, const char *p2, const char *p3, int p4))
DEFINE_METHOD0(int64_t, av_gettime);
BEGIN_METHOD_RESOLVE()
RESOLVE_METHOD_RENAME(av_register_all, av_register_all_dont_call)
RESOLVE_METHOD(av_find_input_format)
RESOLVE_METHOD(url_feof)
RESOLVE_METHOD(av_metadata_get)
RESOLVE_METHOD(av_close_input_file)
RESOLVE_METHOD(av_close_input_stream)
RESOLVE_METHOD(av_read_frame)
RESOLVE_METHOD(av_read_play)
RESOLVE_METHOD(av_read_pause)
RESOLVE_METHOD(av_seek_frame)
RESOLVE_METHOD_RENAME(av_find_stream_info, av_find_stream_info_dont_call)
RESOLVE_METHOD(av_open_input_file)
RESOLVE_METHOD(url_set_interrupt_cb)
RESOLVE_METHOD(av_open_input_stream)
RESOLVE_METHOD(av_probe_input_format)
RESOLVE_METHOD(av_probe_input_format2)
RESOLVE_METHOD(av_probe_input_buffer)
RESOLVE_METHOD(dump_format)
RESOLVE_METHOD(url_fdopen)
RESOLVE_METHOD(url_fopen)
RESOLVE_METHOD(url_fclose)
RESOLVE_METHOD(url_open_dyn_buf)
RESOLVE_METHOD(url_close_dyn_buf)
RESOLVE_METHOD(url_fseek)
RESOLVE_METHOD(get_buffer)
RESOLVE_METHOD(get_partial_buffer)
RESOLVE_METHOD(put_byte)
RESOLVE_METHOD(put_buffer)
RESOLVE_METHOD(put_be24)
RESOLVE_METHOD(put_be32)
RESOLVE_METHOD(put_be16)
RESOLVE_METHOD(avformat_alloc_context)
RESOLVE_METHOD(av_new_stream)
#if LIBAVFORMAT_VERSION_INT < (52<<16 | 45<<8)
RESOLVE_METHOD(guess_format)
#else
RESOLVE_METHOD(av_guess_format)
#endif
RESOLVE_METHOD(av_set_parameters)
RESOLVE_METHOD(av_alloc_put_byte)
RESOLVE_METHOD(av_write_header)
RESOLVE_METHOD(av_write_trailer)
RESOLVE_METHOD(av_write_frame)
RESOLVE_METHOD(av_metadata_set2)
RESOLVE_METHOD(av_gettime)
END_METHOD_RESOLVE()
/* dependencies of libavformat */
DllAvCodec m_dllAvCodec;
// DllAvCore loaded implicitely by m_dllAvCodec
// DllAvUtil loaded implicitely by m_dllAvCodec
public:
void av_register_all()
{
av_register_all_dont_call();
}
int av_find_stream_info(AVFormatContext *ic)
{
return(av_find_stream_info_dont_call(ic));
}
virtual bool Load()
{
if (!m_dllAvCodec.Load())
return false;
return DllDynamic::Load();
}
};
#endif

216
DllAvUtil.h Normal file
View file

@ -0,0 +1,216 @@
#pragma once
/*
* Copyright (C) 2005-2010 Team XBMC
* http://www.xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with XBMC; see the file COPYING. If not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#if (defined HAVE_CONFIG_H) && (!defined WIN32)
#include "config.h"
#endif
#include "DynamicDll.h"
#include "utils/log.h"
#ifndef __GNUC__
#pragma warning(push)
#pragma warning(disable:4244)
#endif
#ifndef AV_NOWARN_DEPRECATED
#define AV_NOWARN_DEPRECATED
#endif
extern "C" {
#if (defined USE_EXTERNAL_FFMPEG)
#if (defined HAVE_LIBAVUTIL_AVUTIL_H)
#include <libavutil/avutil.h>
#include <libavutil/crc.h>
#include <libavutil/fifo.h>
// for LIBAVCODEC_VERSION_INT:
#include <libavcodec/avcodec.h>
#elif (defined HAVE_FFMPEG_AVUTIL_H)
#include <ffmpeg/avutil.h>
#include <ffmpeg/crc.h>
#include <ffmpeg/fifo.h>
// for LIBAVCODEC_VERSION_INT:
#include <ffmpeg/avcodec.h>
#endif
#if defined(HAVE_LIBAVUTIL_OPT_H)
#include <libavutil/opt.h>
#elif defined(HAVE_LIBAVCODEC_AVCODEC_H)
#include <libavcodec/opt.h>
#else
#include <ffmpeg/opt.h>
#endif
#if defined(HAVE_LIBAVUTIL_MEM_H)
#include <libavutil/mem.h>
#else
#include <ffmpeg/mem.h>
#endif
#else
#include "libavutil/avutil.h"
#include "libavutil/crc.h"
#include "libavutil/opt.h"
#include "libavutil/mem.h"
#include "libavutil/fifo.h"
#endif
}
#ifndef __GNUC__
#pragma warning(pop)
#endif
// calback used for logging
//void ff_avutil_log(void* ptr, int level, const char* format, va_list va);
class DllAvUtilInterface
{
public:
virtual ~DllAvUtilInterface() {}
virtual void av_log_set_callback(void (*)(void*, int, const char*, va_list))=0;
virtual void *av_malloc(unsigned int size)=0;
virtual void *av_mallocz(unsigned int size)=0;
virtual void *av_realloc(void *ptr, unsigned int size)=0;
virtual void av_free(void *ptr)=0;
virtual void av_freep(void *ptr)=0;
virtual int64_t av_rescale_rnd(int64_t a, int64_t b, int64_t c, enum AVRounding)=0;
virtual int64_t av_rescale_q(int64_t a, AVRational bq, AVRational cq)=0;
virtual const AVCRC* av_crc_get_table(AVCRCId crc_id)=0;
virtual uint32_t av_crc(const AVCRC *ctx, uint32_t crc, const uint8_t *buffer, size_t length)=0;
virtual int av_set_string3(void *obj, const char *name, const char *val, int alloc, const AVOption **o_out)=0;
virtual AVFifoBuffer *av_fifo_alloc(unsigned int size) = 0;
virtual void av_fifo_free(AVFifoBuffer *f) = 0;
virtual void av_fifo_reset(AVFifoBuffer *f) = 0;
virtual int av_fifo_size(AVFifoBuffer *f) = 0;
virtual int av_fifo_generic_read(AVFifoBuffer *f, void *dest, int buf_size, void (*func)(void*, void*, int)) = 0;
virtual int av_fifo_generic_write(AVFifoBuffer *f, void *src, int size, int (*func)(void*, void*, int)) = 0;
virtual char *av_strdup(const char *s)=0;
virtual void av_log_set_level(int level) = 0;
};
#if (defined USE_EXTERNAL_FFMPEG)
// Use direct layer
class DllAvUtilBase : public DllDynamic, DllAvUtilInterface
{
public:
virtual ~DllAvUtilBase() {}
virtual void av_log_set_callback(void (*foo)(void*, int, const char*, va_list)) { ::av_log_set_callback(foo); }
virtual void *av_malloc(unsigned int size) { return ::av_malloc(size); }
virtual void *av_mallocz(unsigned int size) { return ::av_mallocz(size); }
virtual void *av_realloc(void *ptr, unsigned int size) { return ::av_realloc(ptr, size); }
virtual void av_free(void *ptr) { ::av_free(ptr); }
virtual void av_freep(void *ptr) { ::av_freep(ptr); }
virtual int64_t av_rescale_rnd(int64_t a, int64_t b, int64_t c, enum AVRounding d) { return ::av_rescale_rnd(a, b, c, d); }
virtual int64_t av_rescale_q(int64_t a, AVRational bq, AVRational cq) { return ::av_rescale_q(a, bq, cq); }
virtual const AVCRC* av_crc_get_table(AVCRCId crc_id) { return ::av_crc_get_table(crc_id); }
virtual uint32_t av_crc(const AVCRC *ctx, uint32_t crc, const uint8_t *buffer, size_t length) { return ::av_crc(ctx, crc, buffer, length); }
#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(52,7,0)
// API added on: 2008-12-16
virtual int av_set_string3(void *obj, const char *name, const char *val, int alloc, const AVOption **o_out) { return ::av_set_string3(obj, name, val, alloc, o_out); }
#else
virtual int av_set_string3(void *obj, const char *name, const char *val, int alloc, const AVOption **o_out) { return AVERROR(ENOENT); }
#endif
virtual AVFifoBuffer *av_fifo_alloc(unsigned int size) {return ::av_fifo_alloc(size); }
virtual void av_fifo_free(AVFifoBuffer *f) { ::av_fifo_free(f); }
virtual void av_fifo_reset(AVFifoBuffer *f) { ::av_fifo_reset(f); }
virtual int av_fifo_size(AVFifoBuffer *f) { return ::av_fifo_size(f); }
virtual int av_fifo_generic_read(AVFifoBuffer *f, void *dest, int buf_size, void (*func)(void*, void*, int))
{ return ::av_fifo_generic_read(f, dest, buf_size, func); }
virtual int av_fifo_generic_write(AVFifoBuffer *f, void *src, int size, int (*func)(void*, void*, int))
{ return ::av_fifo_generic_write(f, src, size, func); }
virtual char *av_strdup(const char *s) { return ::av_strdup(s); }
virtual void av_log_set_level(int level) { ::av_log_set_level(level); };
// DLL faking.
virtual bool ResolveExports() { return true; }
virtual bool Load() {
CLog::Log(LOGDEBUG, "DllAvUtilBase: Using libavutil system library");
return true;
}
virtual void Unload() {}
};
#else
class DllAvUtilBase : public DllDynamic, DllAvUtilInterface
{
DECLARE_DLL_WRAPPER(DllAvUtilBase, DLL_PATH_LIBAVUTIL)
LOAD_SYMBOLS()
DEFINE_METHOD1(void, av_log_set_callback, (void (*p1)(void*, int, const char*, va_list)))
DEFINE_METHOD1(void*, av_malloc, (unsigned int p1))
DEFINE_METHOD1(void*, av_mallocz, (unsigned int p1))
DEFINE_METHOD2(void*, av_realloc, (void *p1, unsigned int p2))
DEFINE_METHOD1(void, av_free, (void *p1))
DEFINE_METHOD1(void, av_freep, (void *p1))
DEFINE_METHOD4(int64_t, av_rescale_rnd, (int64_t p1, int64_t p2, int64_t p3, enum AVRounding p4));
DEFINE_METHOD3(int64_t, av_rescale_q, (int64_t p1, AVRational p2, AVRational p3));
DEFINE_METHOD1(const AVCRC*, av_crc_get_table, (AVCRCId p1))
DEFINE_METHOD4(uint32_t, av_crc, (const AVCRC *p1, uint32_t p2, const uint8_t *p3, size_t p4));
DEFINE_METHOD5(int, av_set_string3, (void *p1, const char *p2, const char *p3, int p4, const AVOption **p5));
DEFINE_METHOD1(AVFifoBuffer*, av_fifo_alloc, (unsigned int p1))
DEFINE_METHOD1(void, av_fifo_free, (AVFifoBuffer *p1))
DEFINE_METHOD1(void, av_fifo_reset, (AVFifoBuffer *p1))
DEFINE_METHOD1(int, av_fifo_size, (AVFifoBuffer *p1))
DEFINE_METHOD4(int, av_fifo_generic_read, (AVFifoBuffer *p1, void *p2, int p3, void (*p4)(void*, void*, int)))
DEFINE_METHOD4(int, av_fifo_generic_write, (AVFifoBuffer *p1, void *p2, int p3, int (*p4)(void*, void*, int)))
DEFINE_METHOD1(char*, av_strdup, (const char *p1))
DEFINE_METHOD1(void, av_log_set_level, (int p1))
public:
BEGIN_METHOD_RESOLVE()
RESOLVE_METHOD(av_log_set_callback)
RESOLVE_METHOD(av_malloc)
RESOLVE_METHOD(av_mallocz)
RESOLVE_METHOD(av_realloc)
RESOLVE_METHOD(av_free)
RESOLVE_METHOD(av_freep)
RESOLVE_METHOD(av_rescale_rnd)
RESOLVE_METHOD(av_rescale_q)
RESOLVE_METHOD(av_crc_get_table)
RESOLVE_METHOD(av_crc)
RESOLVE_METHOD(av_set_string3)
RESOLVE_METHOD(av_fifo_alloc)
RESOLVE_METHOD(av_fifo_free)
RESOLVE_METHOD(av_fifo_reset)
RESOLVE_METHOD(av_fifo_size)
RESOLVE_METHOD(av_fifo_generic_read)
RESOLVE_METHOD(av_fifo_generic_write)
RESOLVE_METHOD(av_strdup)
END_METHOD_RESOLVE()
};
#endif
class DllAvUtil : public DllAvUtilBase
{
public:
virtual bool Load()
{
if( DllAvUtilBase::Load() )
{
//DllAvUtilBase::av_log_set_callback(ff_avutil_log);
return true;
}
return false;
}
};

245
DllBCM.h Normal file
View file

@ -0,0 +1,245 @@
#pragma once
/*
* Copyright (C) 2005-2011 Team XBMC
* http://www.xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with XBMC; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#if defined(HAVE_PLATFORM_RASPBERRY_PI)
#if (defined HAVE_CONFIG_H) && (!defined WIN32)
#include "config.h"
#endif
#ifndef __GNUC__
#pragma warning(push)
#pragma warning(disable:4244)
#endif
extern "C" {
#include <bcm_host.h>
}
#include "DynamicDll.h"
#include "utils/log.h"
////////////////////////////////////////////////////////////////////////////////////////////
class DllBcmHostDisplayInterface
{
public:
virtual ~DllBcmHostDisplayInterface() {}
virtual DISPMANX_DISPLAY_HANDLE_T vc_dispmanx_display_open( uint32_t device ) = 0;
virtual DISPMANX_UPDATE_HANDLE_T vc_dispmanx_update_start( int32_t priority ) = 0;
virtual DISPMANX_ELEMENT_HANDLE_T vc_dispmanx_element_add ( DISPMANX_UPDATE_HANDLE_T update, DISPMANX_DISPLAY_HANDLE_T display,
int32_t layer, const VC_RECT_T *dest_rect, DISPMANX_RESOURCE_HANDLE_T src,
const VC_RECT_T *src_rect, DISPMANX_PROTECTION_T protection,
VC_DISPMANX_ALPHA_T *alpha,
DISPMANX_CLAMP_T *clamp, DISPMANX_TRANSFORM_T transform ) = 0;
virtual int vc_dispmanx_update_submit_sync( DISPMANX_UPDATE_HANDLE_T update ) = 0;
virtual int vc_dispmanx_element_remove( DISPMANX_UPDATE_HANDLE_T update, DISPMANX_ELEMENT_HANDLE_T element ) = 0;
virtual int vc_dispmanx_display_close( DISPMANX_DISPLAY_HANDLE_T display ) = 0;
virtual int vc_dispmanx_display_get_info( DISPMANX_DISPLAY_HANDLE_T display, DISPMANX_MODEINFO_T * pinfo ) = 0;
virtual int vc_dispmanx_display_set_background( DISPMANX_UPDATE_HANDLE_T update, DISPMANX_DISPLAY_HANDLE_T display,
uint8_t red, uint8_t green, uint8_t blue ) = 0;
};
#if (defined USE_EXTERNAL_LIBBCM_HOST)
class DllBcmHostDisplay : public DllDynamic, DllBcmHostDisplayInterface
{
public:
virtual DISPMANX_DISPLAY_HANDLE_T vc_dispmanx_display_open( uint32_t device )
{ return ::vc_dispmanx_display_open(device); };
virtual DISPMANX_UPDATE_HANDLE_T vc_dispmanx_update_start( int32_t priority )
{ return ::vc_dispmanx_update_start(priority); };
virtual DISPMANX_ELEMENT_HANDLE_T vc_dispmanx_element_add ( DISPMANX_UPDATE_HANDLE_T update, DISPMANX_DISPLAY_HANDLE_T display,
int32_t layer, const VC_RECT_T *dest_rect, DISPMANX_RESOURCE_HANDLE_T src,
const VC_RECT_T *src_rect, DISPMANX_PROTECTION_T protection,
VC_DISPMANX_ALPHA_T *alpha,
DISPMANX_CLAMP_T *clamp, DISPMANX_TRANSFORM_T transform )
{ return ::vc_dispmanx_element_add(update, display, layer, dest_rect, src, src_rect, protection, alpha, clamp, transform); };
virtual int vc_dispmanx_update_submit_sync( DISPMANX_UPDATE_HANDLE_T update )
{ return ::vc_dispmanx_update_submit_sync(update); };
virtual int vc_dispmanx_element_remove( DISPMANX_UPDATE_HANDLE_T update, DISPMANX_ELEMENT_HANDLE_T element )
{ return ::vc_dispmanx_element_remove(update, element); };
virtual int vc_dispmanx_display_close( DISPMANX_DISPLAY_HANDLE_T display )
{ return ::vc_dispmanx_display_close(display); };
virtual int vc_dispmanx_display_get_info( DISPMANX_DISPLAY_HANDLE_T display, DISPMANX_MODEINFO_T *pinfo )
{ return ::vc_dispmanx_display_get_info(display, pinfo); };
virtual int vc_dispmanx_display_set_background( DISPMANX_UPDATE_HANDLE_T update, DISPMANX_DISPLAY_HANDLE_T display,
uint8_t red, uint8_t green, uint8_t blue )
{ return ::vc_dispmanx_display_set_background(update, display, red, green, blue); };
virtual bool ResolveExports()
{ return true; }
virtual bool Load()
{
CLog::Log(LOGDEBUG, "DllBcm: Using omx system library");
return true;
}
virtual void Unload() {}
};
#else
class DllBcmHostDisplay : public DllDynamic, DllBcmHostDisplayInterface
{
//DECLARE_DLL_WRAPPER(DllBcmHostDisplay, "/opt/vc/lib/libopenmaxil.so")
DECLARE_DLL_WRAPPER(DllBcmHostDisplay, "/opt/vc/lib/libEGL.so")
DEFINE_METHOD1(DISPMANX_DISPLAY_HANDLE_T, vc_dispmanx_display_open, (uint32_t p1 ))
DEFINE_METHOD1(DISPMANX_UPDATE_HANDLE_T, vc_dispmanx_update_start, (int32_t p1 ))
DEFINE_METHOD10(DISPMANX_ELEMENT_HANDLE_T, vc_dispmanx_element_add, (DISPMANX_UPDATE_HANDLE_T p1, DISPMANX_DISPLAY_HANDLE_T p2,
int32_t p3, const VC_RECT_T *p4, DISPMANX_RESOURCE_HANDLE_T p5,
const VC_RECT_T *p6, DISPMANX_PROTECTION_T p7,
VC_DISPMANX_ALPHA_T *p8,
DISPMANX_CLAMP_T *p9, DISPMANX_TRANSFORM_T p10 ))
DEFINE_METHOD1(int, vc_dispmanx_update_submit_sync, (DISPMANX_UPDATE_HANDLE_T p1))
DEFINE_METHOD2(int, vc_dispmanx_element_remove, (DISPMANX_UPDATE_HANDLE_T p1, DISPMANX_ELEMENT_HANDLE_T p2))
DEFINE_METHOD1(int, vc_dispmanx_display_close, (DISPMANX_DISPLAY_HANDLE_T p1))
DEFINE_METHOD2(int, vc_dispmanx_display_get_info, (DISPMANX_DISPLAY_HANDLE_T p1, DISPMANX_MODEINFO_T *p2))
DEFINE_METHOD5(int, vc_dispmanx_display_set_background, ( DISPMANX_UPDATE_HANDLE_T p1, DISPMANX_DISPLAY_HANDLE_T p2,
uint8_t p3, uint8_t p4, uint8_t p5 ))
BEGIN_METHOD_RESOLVE()
RESOLVE_METHOD(vc_dispmanx_display_open)
RESOLVE_METHOD(vc_dispmanx_update_start)
RESOLVE_METHOD(vc_dispmanx_element_add)
RESOLVE_METHOD(vc_dispmanx_update_submit_sync)
RESOLVE_METHOD(vc_dispmanx_element_remove)
RESOLVE_METHOD(vc_dispmanx_display_close)
RESOLVE_METHOD(vc_dispmanx_display_get_info)
RESOLVE_METHOD(vc_dispmanx_display_set_background)
END_METHOD_RESOLVE()
public:
virtual bool Load()
{
return DllDynamic::Load();
}
};
#endif
class DllBcmHostInterface
{
public:
virtual ~DllBcmHostInterface() {}
virtual void bcm_host_init() = 0;
virtual void bcm_host_deinit() = 0;
virtual int32_t graphics_get_display_size( const uint16_t display_number, uint32_t *width, uint32_t *height) = 0;
virtual int vc_tv_hdmi_power_on_best(uint32_t width, uint32_t height, uint32_t frame_rate,
HDMI_INTERLACED_T scan_mode, EDID_MODE_MATCH_FLAG_T match_flags) = 0;
virtual int vc_tv_hdmi_power_on_best_3d(uint32_t width, uint32_t height, uint32_t frame_rate,
HDMI_INTERLACED_T scan_mode, EDID_MODE_MATCH_FLAG_T match_flags) = 0;
virtual int vc_tv_hdmi_get_supported_modes(HDMI_RES_GROUP_T group, TV_SUPPORTED_MODE_T *supported_modes,
uint32_t max_supported_modes, HDMI_RES_GROUP_T *preferred_group,
uint32_t *preferred_mode) = 0;
virtual int vc_tv_hdmi_power_on_explicit(HDMI_MODE_T mode, HDMI_RES_GROUP_T group, uint32_t code) = 0;
virtual int vc_tv_get_state(TV_GET_STATE_RESP_T *tvstate) = 0;
virtual void vc_tv_register_callback(TVSERVICE_CALLBACK_T callback, void *callback_data) = 0;
virtual void vc_tv_unregister_callback(TVSERVICE_CALLBACK_T callback) = 0;
virtual void vc_cec_register_callback(CECSERVICE_CALLBACK_T callback, void *callback_data) = 0;
//virtual void vc_cec_unregister_callback(CECSERVICE_CALLBACK_T callback) = 0;
};
#if (defined USE_EXTERNAL_LIBBCM_HOST)
class DllBcmHost : public DllDynamic, DllBcmHostInterface
{
public:
virtual void bcm_host_init()
{ return ::bcm_host_init(); };
virtual void bcm_host_deinit()
{ return ::bcm_host_deinit(); };
virtual int32_t graphics_get_display_size( const uint16_t display_number, uint32_t *width, uint32_t *height)
{ return ::graphics_get_display_size(display_number, width, height); };
virtual int vc_tv_hdmi_power_on_best(uint32_t width, uint32_t height, uint32_t frame_rate,
HDMI_INTERLACED_T scan_mode, EDID_MODE_MATCH_FLAG_T match_flags)
{ return ::vc_tv_hdmi_power_on_best(width, height, frame_rate, scan_mode, match_flags); };
virtual int vc_tv_hdmi_power_on_best_3d(uint32_t width, uint32_t height, uint32_t frame_rate,
HDMI_INTERLACED_T scan_mode, EDID_MODE_MATCH_FLAG_T match_flags)
{ return ::vc_tv_hdmi_power_on_best_3d(width, height, frame_rate, scan_mode, match_flags); };
virtual int vc_tv_hdmi_get_supported_modes(HDMI_RES_GROUP_T group, TV_SUPPORTED_MODE_T *supported_modes,
uint32_t max_supported_modes, HDMI_RES_GROUP_T *preferred_group,
uint32_t *preferred_mode)
{ return ::vc_tv_hdmi_get_supported_modes(group, supported_modes, max_supported_modes, preferred_group, preferred_mode); };
virtual int vc_tv_hdmi_power_on_explicit(HDMI_MODE_T mode, HDMI_RES_GROUP_T group, uint32_t code)
{ return ::vc_tv_hdmi_power_on_explicit(mode, group, code); };
virtual int vc_tv_get_state(TV_GET_STATE_RESP_T *tvstate)
{ return ::vc_tv_get_state(tvstate); };
virtual void vc_tv_register_callback(TVSERVICE_CALLBACK_T callback, void *callback_data)
{ ::vc_tv_register_callback(callback, callback_data); };
virtual void vc_tv_unregister_callback(TVSERVICE_CALLBACK_T callback)
{ ::vc_tv_unregister_callback(callback); };
virtual void vc_cec_register_callback(CECSERVICE_CALLBACK_T callback, void *callback_data)
{ ::vc_cec_register_callback(callback, callback_data); };
//virtual void vc_cec_unregister_callback(CECSERVICE_CALLBACK_T callback)
// { ::vc_cec_unregister_callback(callback); };
virtual bool ResolveExports()
{ return true; }
virtual bool Load()
{
CLog::Log(LOGDEBUG, "DllBcm: Using omx system library");
return true;
}
virtual void Unload() {}
};
#else
class DllBcmHost : public DllDynamic, DllBcmHostInterface
{
DECLARE_DLL_WRAPPER(DllBcmHost, "/opt/vc/lib/libbcm_host.so")
DEFINE_METHOD0(void, bcm_host_init)
DEFINE_METHOD0(void, bcm_host_deinit)
DEFINE_METHOD3(int32_t, graphics_get_display_size, (const uint16_t p1, uint32_t *p2, uint32_t *p3))
DEFINE_METHOD5(int, vc_tv_hdmi_power_on_best, (uint32_t p1, uint32_t p2, uint32_t p3,
HDMI_INTERLACED_T p4, EDID_MODE_MATCH_FLAG_T p5))
DEFINE_METHOD5(int, vc_tv_hdmi_power_on_best_3d, (uint32_t p1, uint32_t p2, uint32_t p3,
HDMI_INTERLACED_T p4, EDID_MODE_MATCH_FLAG_T p5))
DEFINE_METHOD5(int, vc_tv_hdmi_get_supported_modes, (HDMI_RES_GROUP_T p1, TV_SUPPORTED_MODE_T *p2,
uint32_t p3, HDMI_RES_GROUP_T *p4, uint32_t *p5))
DEFINE_METHOD3(int, vc_tv_hdmi_power_on_explicit, (HDMI_MODE_T p1, HDMI_RES_GROUP_T p2, uint32_t p3))
DEFINE_METHOD1(int, vc_tv_get_state, (TV_GET_STATE_RESP_T *p1))
DEFINE_METHOD2(void, vc_tv_register_callback, (TVSERVICE_CALLBACK_T p1, void *p2))
DEFINE_METHOD1(void, vc_tv_unregister_callback, (TVSERVICE_CALLBACK_T p1))
DEFINE_METHOD2(void, vc_cec_register_callback, (CECSERVICE_CALLBACK_T p1, void *p2))
//DEFINE_METHOD1(void, vc_cec_unregister_callback, (CECSERVICE_CALLBACK_T p1))
BEGIN_METHOD_RESOLVE()
RESOLVE_METHOD(bcm_host_init)
RESOLVE_METHOD(bcm_host_deinit)
RESOLVE_METHOD(graphics_get_display_size)
RESOLVE_METHOD(vc_tv_hdmi_power_on_best)
RESOLVE_METHOD(vc_tv_hdmi_power_on_best_3d)
RESOLVE_METHOD(vc_tv_hdmi_get_supported_modes)
RESOLVE_METHOD(vc_tv_hdmi_power_on_explicit)
RESOLVE_METHOD(vc_tv_get_state)
RESOLVE_METHOD(vc_tv_register_callback)
RESOLVE_METHOD(vc_tv_unregister_callback)
RESOLVE_METHOD(vc_cec_register_callback)
//RESOLVE_METHOD(vc_cec_unregister_callback)
END_METHOD_RESOLVE()
public:
virtual bool Load()
{
return DllDynamic::Load();
}
};
#endif
#endif

123
DllOMX.h Normal file
View file

@ -0,0 +1,123 @@
#pragma once
/*
* Copyright (C) 2005-2010 Team XBMC
* http://www.xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with XBMC; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#if defined(HAVE_OMXLIB)
#if (defined HAVE_CONFIG_H) && (!defined WIN32)
#include "config.h"
#endif
#ifndef __GNUC__
#pragma warning(push)
#pragma warning(disable:4244)
#endif
#include "DynamicDll.h"
#include "utils/log.h"
#include <IL/OMX_Core.h>
#include <IL/OMX_Component.h>
#include <IL/OMX_Index.h>
#include <IL/OMX_Image.h>
#include <IL/OMX_Video.h>
#include <IL/OMX_Broadcom.h>
////////////////////////////////////////////////////////////////////////////////////////////
class DllOMXInterface
{
public:
virtual ~DllOMXInterface() {}
virtual OMX_ERRORTYPE OMX_Init(void) = 0;
virtual OMX_ERRORTYPE OMX_Deinit(void) = 0;
virtual OMX_ERRORTYPE OMX_GetHandle(OMX_HANDLETYPE *pHandle, OMX_STRING cComponentName, OMX_PTR pAppData, OMX_CALLBACKTYPE *pCallBacks) = 0;
virtual OMX_ERRORTYPE OMX_FreeHandle(OMX_HANDLETYPE hComponent) = 0;
virtual OMX_ERRORTYPE OMX_GetComponentsOfRole(OMX_STRING role, OMX_U32 *pNumComps, OMX_U8 **compNames) = 0;
virtual OMX_ERRORTYPE OMX_GetRolesOfComponent(OMX_STRING compName, OMX_U32 *pNumRoles, OMX_U8 **roles) = 0;
virtual OMX_ERRORTYPE OMX_ComponentNameEnum(OMX_STRING cComponentName, OMX_U32 nNameLength, OMX_U32 nIndex) = 0;
virtual OMX_ERRORTYPE OMX_SetupTunnel(OMX_HANDLETYPE hOutput, OMX_U32 nPortOutput, OMX_HANDLETYPE hInput, OMX_U32 nPortInput) = 0;
};
#if (defined USE_EXTERNAL_OMX)
class DllOMX : public DllDynamic, DllOMXInterface
{
public:
virtual OMX_ERRORTYPE OMX_Init(void)
{ return ::OMX_Init(); };
virtual OMX_ERRORTYPE OMX_Deinit(void)
{ return ::OMX_Deinit(); };
virtual OMX_ERRORTYPE OMX_GetHandle(OMX_HANDLETYPE *pHandle, OMX_STRING cComponentName, OMX_PTR pAppData, OMX_CALLBACKTYPE *pCallBacks)
{ return ::OMX_GetHandle(pHandle, cComponentName, pAppData, pCallBacks); };
virtual OMX_ERRORTYPE OMX_FreeHandle(OMX_HANDLETYPE hComponent)
{ return ::OMX_FreeHandle(hComponent); };
virtual OMX_ERRORTYPE OMX_GetComponentsOfRole(OMX_STRING role, OMX_U32 *pNumComps, OMX_U8 **compNames)
{ return ::OMX_GetComponentsOfRole(role, pNumComps, compNames); };
virtual OMX_ERRORTYPE OMX_GetRolesOfComponent(OMX_STRING compName, OMX_U32 *pNumRoles, OMX_U8 **roles)
{ return ::OMX_GetRolesOfComponent(compName, pNumRoles, roles); };
virtual OMX_ERRORTYPE OMX_ComponentNameEnum(OMX_STRING cComponentName, OMX_U32 nNameLength, OMX_U32 nIndex)
{ return ::OMX_ComponentNameEnum(cComponentName, nNameLength, nIndex); };
virtual OMX_ERRORTYPE OMX_SetupTunnel(OMX_HANDLETYPE hOutput, OMX_U32 nPortOutput, OMX_HANDLETYPE hInput, OMX_U32 nPortInput)
{ return ::OMX_SetupTunnel(hOutput, nPortOutput, hInput, nPortInput); };
virtual bool ResolveExports()
{ return true; }
virtual bool Load()
{
CLog::Log(LOGDEBUG, "DllOMX: Using omx system library");
return true;
}
virtual void Unload() {}
};
#else
class DllOMX : public DllDynamic, DllOMXInterface
{
//DECLARE_DLL_WRAPPER(DllLibOpenMax, "/usr/lib/libnvomx.so")
DECLARE_DLL_WRAPPER(DllOMX, "/opt/vc/lib/libopenmaxil.so")
DEFINE_METHOD0(OMX_ERRORTYPE, OMX_Init)
DEFINE_METHOD0(OMX_ERRORTYPE, OMX_Deinit)
DEFINE_METHOD4(OMX_ERRORTYPE, OMX_GetHandle, (OMX_HANDLETYPE *p1, OMX_STRING p2, OMX_PTR p3, OMX_CALLBACKTYPE *p4))
DEFINE_METHOD1(OMX_ERRORTYPE, OMX_FreeHandle, (OMX_HANDLETYPE p1))
DEFINE_METHOD3(OMX_ERRORTYPE, OMX_GetComponentsOfRole, (OMX_STRING p1, OMX_U32 *p2, OMX_U8 **p3))
DEFINE_METHOD3(OMX_ERRORTYPE, OMX_GetRolesOfComponent, (OMX_STRING p1, OMX_U32 *p2, OMX_U8 **p3))
DEFINE_METHOD3(OMX_ERRORTYPE, OMX_ComponentNameEnum, (OMX_STRING p1, OMX_U32 p2, OMX_U32 p3))
DEFINE_METHOD4(OMX_ERRORTYPE, OMX_SetupTunnel, (OMX_HANDLETYPE p1, OMX_U32 p2, OMX_HANDLETYPE p3, OMX_U32 p4));
BEGIN_METHOD_RESOLVE()
RESOLVE_METHOD(OMX_Init)
RESOLVE_METHOD(OMX_Deinit)
RESOLVE_METHOD(OMX_GetHandle)
RESOLVE_METHOD(OMX_FreeHandle)
RESOLVE_METHOD(OMX_GetComponentsOfRole)
RESOLVE_METHOD(OMX_GetRolesOfComponent)
RESOLVE_METHOD(OMX_ComponentNameEnum)
RESOLVE_METHOD(OMX_SetupTunnel)
END_METHOD_RESOLVE()
public:
virtual bool Load()
{
return DllDynamic::Load();
}
};
#endif
#endif

95
DynamicDll.cpp Normal file
View file

@ -0,0 +1,95 @@
/*
* Copyright (C) 2005-2008 Team XBMC
* http://www.xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with XBMC; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#include "DynamicDll.h"
#include "utils/log.h"
DllDynamic::DllDynamic()
{
m_dll=NULL;
m_DelayUnload=true;
}
DllDynamic::DllDynamic(const CStdString& strDllName)
{
m_strDllName=strDllName;
m_dll=NULL;
m_DelayUnload=true;
}
DllDynamic::~DllDynamic()
{
Unload();
}
bool DllDynamic::Load()
{
if (m_dll)
return true;
/*
if (!(m_dll=CSectionLoader::LoadDLL(m_strDllName, m_DelayUnload, LoadSymbols())))
return false;
if (!ResolveExports())
{
CLog::Log(LOGERROR, "Unable to resolve exports from dll %s", m_strDllName.c_str());
Unload();
return false;
}
*/
return true;
}
void DllDynamic::Unload()
{
/*
if(m_dll)
CSectionLoader::UnloadDLL(m_strDllName);
*/
m_dll=NULL;
}
bool DllDynamic::CanLoad()
{
return true;
}
bool DllDynamic::EnableDelayedUnload(bool bOnOff)
{
if (m_dll)
return false;
m_DelayUnload=bOnOff;
return true;
}
bool DllDynamic::SetFile(const CStdString& strDllName)
{
if (m_dll)
return false;
m_strDllName=strDllName;
return true;
}

497
DynamicDll.h Normal file
View file

@ -0,0 +1,497 @@
#pragma once
/*
* Copyright (C) 2005-2008 Team XBMC
* http://www.xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with XBMC; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#include "utils/StdString.h"
///////////////////////////////////////////////////////////
//
// DECLARE_DLL_WRAPPER
//
// Declares the constructor of the wrapper class.
// This must be followed by one or more
// DEFINE_METHODX/DEFINE_METHOD_LINKAGEX and
// one BEGIN_METHOD_RESOLVE/END_METHOD_RESOLVE block.
//
// classname: name of the wrapper class to construct
// dllname: file including path of the dll to wrap
#define DECLARE_DLL_WRAPPER(classname, dllname) \
XDECLARE_DLL_WRAPPER(classname,dllname)
#define XDECLARE_DLL_WRAPPER(classname, dllname) \
public: \
classname () : DllDynamic( dllname ) {}
///////////////////////////////////////////////////////////
//
// DECLARE_DLL_WRAPPER_TEMPLATE_BEGIN
//
// Declares the constructor of the wrapper class.
// The method SetFile(strDllName) can be used to set the
// dll of this wrapper.
// This must be followed by one or more
// DEFINE_METHODX/DEFINE_METHOD_LINKAGEX and
// one BEGIN_METHOD_RESOLVE/END_METHOD_RESOLVE block.
//
// classname: name of the wrapper class to construct
//
#define DECLARE_DLL_WRAPPER_TEMPLATE(classname) \
public: \
classname () {} \
///////////////////////////////////////////////////////////
//
// LOAD_SYMBOLS
//
// Tells the dllloader to load Debug symblos when possible
#define LOAD_SYMBOLS() \
protected: \
virtual bool LoadSymbols() { return true; }
///////////////////////////////////////////////////////////
//
// DEFINE_GLOBAL
//
// Defines a global for export from the dll as well as
// a function for accessing it (Get_name).
//
// type: The variables type.
// name: Name of the variable.
//
#define DEFINE_GLOBAL_PTR(type, name) \
protected: \
union { \
type* m_##name; \
void* m_##name##_ptr; \
}; \
public: \
virtual type* Get_##name (void) \
{ \
return m_##name; \
}
#define DEFINE_GLOBAL(type, name) \
protected: \
union { \
type* m_##name; \
void* m_##name##_ptr; \
}; \
public: \
virtual type Get_##name (void) \
{ \
return *m_##name; \
}
///////////////////////////////////////////////////////////
//
// DEFINE_METHOD_LINKAGE
//
// Defines a function for an export from a dll, if the
// calling convention is not __cdecl.
// Use DEFINE_METHOD_LINKAGE for each function to be resolved.
//
// result: Result of the function
// linkage: Calling convention of the function
// name: Name of the function
// args: Arguments of the function, enclosed in parentheses
//
#define DEFINE_METHOD_LINKAGE_FP(result, linkage, name, args) \
protected: \
typedef result (linkage * name##_METHOD) args; \
public: \
union { \
name##_METHOD name; \
void* name##_ptr; \
};
#define DEFINE_METHOD_LINKAGE_BASE(result, linkage, name, args, args2) \
protected: \
typedef result (linkage * name##_METHOD) args; \
union { \
name##_METHOD m_##name; \
void* m_##name##_ptr; \
}; \
public: \
virtual result name args \
{ \
return m_##name args2; \
}
#define DEFINE_METHOD_LINKAGE0(result, linkage, name) \
DEFINE_METHOD_LINKAGE_BASE(result, linkage, name, () , ())
#define DEFINE_METHOD_LINKAGE1(result, linkage, name, args) \
DEFINE_METHOD_LINKAGE_BASE(result, linkage, name, args, (p1))
#define DEFINE_METHOD_LINKAGE2(result, linkage, name, args) \
DEFINE_METHOD_LINKAGE_BASE(result, linkage, name, args, (p1, p2))
#define DEFINE_METHOD_LINKAGE3(result, linkage, name, args) \
DEFINE_METHOD_LINKAGE_BASE(result, linkage, name, args, (p1, p2, p3))
#define DEFINE_METHOD_LINKAGE4(result, linkage, name, args) \
DEFINE_METHOD_LINKAGE_BASE(result, linkage, name, args, (p1, p2, p3, p4))
#define DEFINE_METHOD_LINKAGE5(result, linkage, name, args) \
DEFINE_METHOD_LINKAGE_BASE(result, linkage, name, args, (p1, p2, p3, p4, p5))
#define DEFINE_METHOD_LINKAGE6(result, linkage, name, args) \
DEFINE_METHOD_LINKAGE_BASE(result, linkage, name, args, (p1, p2, p3, p4, p5, p6))
#define DEFINE_METHOD_LINKAGE7(result, linkage, name, args) \
DEFINE_METHOD_LINKAGE_BASE(result, linkage, name, args, (p1, p2, p3, p4, p5, p6, p7))
#define DEFINE_METHOD_LINKAGE8(result, linkage, name, args) \
DEFINE_METHOD_LINKAGE_BASE(result, linkage, name, args, (p1, p2, p3, p4, p5, p6, p7, p8))
#define DEFINE_METHOD_LINKAGE9(result, linkage, name, args) \
DEFINE_METHOD_LINKAGE_BASE(result, linkage, name, args, (p1, p2, p3, p4, p5, p6, p7, p8, p9))
#define DEFINE_METHOD_LINKAGE10(result, linkage, name, args) \
DEFINE_METHOD_LINKAGE_BASE(result, linkage, name, args, (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10))
#define DEFINE_METHOD_LINKAGE11(result, linkage, name, args) \
DEFINE_METHOD_LINKAGE_BASE(result, linkage, name, args, (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11))
///////////////////////////////////////////////////////////
//
// DEFINE_METHOD_FP
//
// Defines a function for an export from a dll as a fuction pointer.
// Use DEFINE_METHOD_FP for each function to be resolved. Functions
// defined like this are not listed by IntelliSence.
//
// result: Result of the function
// name: Name of the function
// args: Arguments of the function, enclosed in parentheses
// The parameter names can be anything
//
#define DEFINE_METHOD_FP(result, name, args) DEFINE_METHOD_LINKAGE_FP(result, __cdecl, name, args)
///////////////////////////////////////////////////////////
//
// DEFINE_METHODX
//
// Defines a function for an export from a dll.
// Use DEFINE_METHODX for each function to be resolved.
// where X is the number of parameter the function has.
//
// result: Result of the function
// name: Name of the function
// args: Arguments of the function, enclosed in parentheses
// The parameter names have to be renamed to px, where
// x is the number of the parameter
//
#define DEFINE_METHOD0(result, name) DEFINE_METHOD_LINKAGE0(result, __cdecl, name)
#define DEFINE_METHOD1(result, name, args) DEFINE_METHOD_LINKAGE1(result, __cdecl, name, args)
#define DEFINE_METHOD2(result, name, args) DEFINE_METHOD_LINKAGE2(result, __cdecl, name, args)
#define DEFINE_METHOD3(result, name, args) DEFINE_METHOD_LINKAGE3(result, __cdecl, name, args)
#define DEFINE_METHOD4(result, name, args) DEFINE_METHOD_LINKAGE4(result, __cdecl, name, args)
#define DEFINE_METHOD5(result, name, args) DEFINE_METHOD_LINKAGE5(result, __cdecl, name, args)
#define DEFINE_METHOD6(result, name, args) DEFINE_METHOD_LINKAGE6(result, __cdecl, name, args)
#define DEFINE_METHOD7(result, name, args) DEFINE_METHOD_LINKAGE7(result, __cdecl, name, args)
#define DEFINE_METHOD8(result, name, args) DEFINE_METHOD_LINKAGE8(result, __cdecl, name, args)
#define DEFINE_METHOD9(result, name, args) DEFINE_METHOD_LINKAGE9(result, __cdecl, name, args)
#define DEFINE_METHOD10(result, name, args) DEFINE_METHOD_LINKAGE10(result, __cdecl, name, args)
#define DEFINE_METHOD11(result, name, args) DEFINE_METHOD_LINKAGE11(result, __cdecl, name, args)
///////////////////////////////////////////////////////////
//
// DEFINE_FUNC_ALIGNED 0-X
//
// Defines a function for an export from a dll, wich
// require a aligned stack on function call
// Use DEFINE_FUNC_ALIGNED for each function to be resolved.
//
// result: Result of the function
// linkage: Calling convention of the function
// name: Name of the function
// args: Argument types of the function
//
// Actual function call will expand to something like this
// this will align the stack (esp) at the point of function
// entry as required by gcc compiled dlls, it is abit abfuscated
// to allow for different sized variables
//
// __int64 test(__int64 p1, char p2, char p3)
// {
// int o,s = ((sizeof(p1)+3)&~3)+((sizeof(p2)+3)&~3)+((sizeof(p3)+3)&~3);
// __asm mov [o],esp;
// __asm sub esp, [s];
// __asm and esp, ~15;
// __asm add esp, [s]
// m_test(p1, p2, p3); //return value will still be correct aslong as we don't mess with it
// __asm mov esp,[o];
// };
#define ALS(a) ((sizeof(a)+3)&~3)
#define DEFINE_FUNC_PART1(result, linkage, name, args) \
private: \
typedef result (linkage * name##_type)##args; \
union { \
name##_type m_##name; \
void* m_##name##_ptr; \
}; \
public: \
virtual result name##args
#define DEFINE_FUNC_PART2(size) \
{ \
int o,s = size; \
__asm { \
__asm mov [o], esp \
__asm sub esp, [s] \
__asm and esp, ~15 \
__asm add esp, [s] \
}
#define DEFINE_FUNC_PART3(name,args) \
m_##name##args; \
__asm { \
__asm mov esp,[o] \
} \
}
#define DEFINE_FUNC_ALIGNED0(result, linkage, name) \
DEFINE_FUNC_PART1(result, linkage, name, ()) \
DEFINE_FUNC_PART2(0) \
DEFINE_FUNC_PART3(name,())
#define DEFINE_FUNC_ALIGNED1(result, linkage, name, t1) \
DEFINE_FUNC_PART1(result, linkage, name, (t1 p1)) \
DEFINE_FUNC_PART2(ALS(p1)) \
DEFINE_FUNC_PART3(name,(p1))
#define DEFINE_FUNC_ALIGNED2(result, linkage, name, t1, t2) \
DEFINE_FUNC_PART1(result, linkage, name, (t1 p1, t2 p2)) \
DEFINE_FUNC_PART2(ALS(p1)+ALS(p2)) \
DEFINE_FUNC_PART3(name,(p1, p2))
#define DEFINE_FUNC_ALIGNED3(result, linkage, name, t1, t2, t3) \
DEFINE_FUNC_PART1(result, linkage, name, (t1 p1, t2 p2, t3 p3)) \
DEFINE_FUNC_PART2(ALS(p1)+ALS(p2)+ALS(p3)) \
DEFINE_FUNC_PART3(name,(p1, p2, p3))
#define DEFINE_FUNC_ALIGNED4(result, linkage, name, t1, t2, t3, t4) \
DEFINE_FUNC_PART1(result, linkage, name, (t1 p1, t2 p2, t3 p3, t4 p4)) \
DEFINE_FUNC_PART2(ALS(p1)+ALS(p2)+ALS(p3)+ALS(p4)) \
DEFINE_FUNC_PART3(name,(p1, p2, p3, p4))
#define DEFINE_FUNC_ALIGNED5(result, linkage, name, t1, t2, t3, t4, t5) \
DEFINE_FUNC_PART1(result, linkage, name, (t1 p1, t2 p2, t3 p3, t4 p4, t5 p5)) \
DEFINE_FUNC_PART2(ALS(p1)+ALS(p2)+ALS(p3)+ALS(p4)+ALS(p5)) \
DEFINE_FUNC_PART3(name,(p1, p2, p3, p4, p5))
#define DEFINE_FUNC_ALIGNED6(result, linkage, name, t1, t2, t3, t4, t5, t6) \
DEFINE_FUNC_PART1(result, linkage, name, (t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6)) \
DEFINE_FUNC_PART2(ALS(p1)+ALS(p2)+ALS(p3)+ALS(p4)+ALS(p5)+ALS(p6)) \
DEFINE_FUNC_PART3(name,(p1, p2, p3, p4, p5, p6))
#define DEFINE_FUNC_ALIGNED7(result, linkage, name, t1, t2, t3, t4, t5, t6, t7) \
DEFINE_FUNC_PART1(result, linkage, name, (t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7)) \
DEFINE_FUNC_PART2(ALS(p1)+ALS(p2)+ALS(p3)+ALS(p4)+ALS(p5)+ALS(p6)+ALS(p7)) \
DEFINE_FUNC_PART3(name,(p1, p2, p3, p4, p5, p6, p7))
#define DEFINE_FUNC_ALIGNED8(result, linkage, name, t1, t2, t3, t4, t5, t6, t7, t8) \
DEFINE_FUNC_PART1(result, linkage, name, (t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, t8 p8)) \
DEFINE_FUNC_PART2(ALS(p1)+ALS(p2)+ALS(p3)+ALS(p4)+ALS(p5)+ALS(p6)+ALS(p7)+ALS(p8)) \
DEFINE_FUNC_PART3(name,(p1, p2, p3, p4, p5, p6, p7, p8))
#define DEFINE_FUNC_ALIGNED9(result, linkage, name, t1, t2, t3, t4, t5, t6, t7, t8, t9) \
DEFINE_FUNC_PART1(result, linkage, name, (t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, t8 p8, t9 p9)) \
DEFINE_FUNC_PART2(ALS(p1)+ALS(p2)+ALS(p3)+ALS(p4)+ALS(p5)+ALS(p6)+ALS(p7)+ALS(p8)+ALS(p9)) \
DEFINE_FUNC_PART3(name,(p1, p2, p3, p4, p5, p6, p7, p8, p9))
///////////////////////////////////////////////////////////
//
// BEGIN_METHOD_RESOLVE/END_METHOD_RESOLVE
//
// Defines a method that resolves the exported functions
// defined with DEFINE_METHOD or DEFINE_METHOD_LINKAGE.
// There must be a RESOLVE_METHOD or RESOLVE_METHOD_RENAME
// for each DEFINE_METHOD or DEFINE_METHOD_LINKAGE within this
// block. This block must be followed by an END_METHOD_RESOLVE.
//
#define BEGIN_METHOD_RESOLVE() \
protected: \
virtual bool ResolveExports() \
{ \
return (
#define END_METHOD_RESOLVE() \
1 \
); \
}
///////////////////////////////////////////////////////////
//
// RESOLVE_METHOD
//
// Resolves a method from a dll
//
// method: Name of the method defined with DEFINE_METHOD
// or DEFINE_METHOD_LINKAGE
//
#define RESOLVE_METHOD(method) \
m_dll->ResolveExport( #method , & m_##method##_ptr ) &&
#define RESOLVE_METHOD_FP(method) \
m_dll->ResolveExport( #method , & method##_ptr ) &&
///////////////////////////////////////////////////////////
//
// RESOLVE_METHOD_RENAME
//
// Resolves a method from a dll
//
// dllmethod: Name of the function exported from the dll
// method: Name of the method defined with DEFINE_METHOD
// or DEFINE_METHOD_LINKAGE
//
#define RESOLVE_METHOD_RENAME(dllmethod, method) \
m_dll->ResolveExport( #dllmethod , & m_##method##_ptr ) &&
#define RESOLVE_METHOD_RENAME_FP(dllmethod, method) \
m_dll->ResolveExport( #dllmethod , & method##_ptr ) &&
////////////////////////////////////////////////////////////////////
//
// Example declaration of a dll wrapper class
//
// 1. Define a class with pure virtual functions with all functions
// exported from the dll. This is needed to use the IntelliSence
// feature of the Visual Studio Editor.
//
// class DllExampleInterface
// {
// public:
// virtual void foo (unsigned int type, char* szTest)=0;
// virtual void bar (char* szTest, unsigned int type)=0;
// };
//
// 2. Define a class, derived from DllDynamic and the previously defined
// interface class. Define the constructor of the class using the
// DECLARE_DLL_WRAPPER macro. Use the DEFINE_METHODX/DEFINE_METHOD_LINKAGEX
// macros to define the functions from the interface above, where X is number of
// parameters the function has. The function parameters
// have to be enclosed in parentheses. The parameter names have to be changed to px
// where x is the number on which position the parameter appears.
// Use the RESOLVE_METHOD/RESOLVE_METHOD_RENAME to do the actually resolve the functions
// from the dll when it's loaded. The RESOLVE_METHOD/RESOLVE_METHOD_RENAME have to
// be between the BEGIN_METHOD_RESOLVE/END_METHOD_RESOLVE block.
//
// class DllExample : public DllDynamic, DllExampleInterface
// {
// DECLARE_DLL_WRAPPER(DllExample, special://xbmcbin/system/Example.dll)
// LOAD_SYMBOLS() // add this if you want to load debug symbols for the dll
// DEFINE_METHOD2(void, foo, (int p1, char* p2))
// DEFINE_METHOD_LINKAGE2(void, __stdcall, bar, (char* p1, int p2))
// DEFINE_METHOD_FP(void, foobar, (int type, char* szTest)) // No need to define this function in the
// // interface class, as it's a function pointer.
// // But its not recognised by IntelliSence
// BEGIN_METHOD_RESOLVE()
// RESOLVE_METHOD(foo)
// RESOLVE_METHOD_RENAME("_bar@8", bar)
// RESOLVE_METHOD_FP(foobar)
// END_METHOD_RESOLVE()
// };
//
// The above macros will expand to a class that will look like this
//
// class DllExample : public DllDynamic, DllExampleInterface
// {
// public:
// DllExample() : DllDynamic( "special://xbmcbin/system/Example.dll" ) {}
// protected:
// virtual bool LoadSymbols() { return true; }
// protected:
// typedef void (* foo_METHOD) ( int p1, char* p2 );
// foo_METHOD m_foo;
// public:
// virtual void foo( int p1, char* p2 )
// {
// return m_foo(p1, p2);
// }
// protected:
// typedef void (__stdcall * bar_METHOD) ( char* p1, int p2 );
// bar_METHOD m_bar;
// public:
// virtual void bar( char* p1, int p2 )
// {
// return m_bar(p1, p2);
// }
// protected:
// typedef void (* foobar_METHOD) (int type, char* szTest);
// public:
// foobar_METHOD foobar;
// protected:
// virtual bool ResolveExports()
// {
// return (
// m_dll->ResolveExport( "foo", (void**)& m_foo ) &&
// m_dll->ResolveExport( "_bar@8", (void**)& m_bar ) &&
// m_dll->ResolveExport( "foobar" , (void**)& foobar ) &&
// 1
// );
// }
// };
//
// Usage of the class
//
// DllExample dll;
// dll.Load();
// if (dll.IsLoaded())
// {
// dll.foo(1, "bar");
// dll.Unload();
// }
//
///////////////////////////////////////////////////////////
//
// Baseclass for a Dynamically loaded dll
// use the above macros to create a dll wrapper
//
class DllDynamic
{
public:
DllDynamic();
DllDynamic(const CStdString& strDllName);
virtual ~DllDynamic();
virtual bool Load();
virtual void Unload();
virtual bool IsLoaded() { return m_dll!=NULL; }
bool CanLoad();
bool EnableDelayedUnload(bool bOnOff);
bool SetFile(const CStdString& strDllName);
protected:
virtual bool ResolveExports()=0;
virtual bool LoadSymbols() { return false; }
bool m_DelayUnload;
void *m_dll;
CStdString m_strDllName;
};

142
File.cpp Normal file
View file

@ -0,0 +1,142 @@
/*
* XBMC Media Center
* Copyright (c) 2002 Frodo
* Portions Copyright (c) by the authors of ffmpeg and xvid
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "linux/PlatformDefs.h"
#include <iostream>
#include <stdio.h>
#include "utils/StdString.h"
#include "File.h"
using namespace XFILE;
using namespace std;
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
#ifndef __GNUC__
#pragma warning (disable:4244)
#endif
//*********************************************************************************************
CFile::CFile()
{
m_pFile = NULL;
m_flags = 0;
m_iLength = 0;
}
//*********************************************************************************************
CFile::~CFile()
{
if (m_pFile)
fclose(m_pFile);
}
//*********************************************************************************************
bool CFile::Open(const CStdString& strFileName, unsigned int flags)
{
m_flags = flags;
m_pFile = fopen64(strFileName.c_str(), "r");
if(!m_pFile)
return false;
fseeko64(m_pFile, 0, SEEK_END);
m_iLength = ftello64(m_pFile);
fseeko64(m_pFile, 0, SEEK_SET);
return true;
}
bool CFile::OpenForWrite(const CStdString& strFileName, bool bOverWrite)
{
return false;
}
bool CFile::Exists(const CStdString& strFileName, bool bUseCache /* = true */)
{
FILE *fp = fopen64(strFileName.c_str(), "r");
if(!fp)
return false;
fclose(fp);
return true;
}
unsigned int CFile::Read(void *lpBuf, int64_t uiBufSize)
{
unsigned int ret = 0;
if(!m_pFile)
return 0;
ret = fread(lpBuf, 1, uiBufSize, m_pFile);
return ret;
}
//*********************************************************************************************
void CFile::Close()
{
if(m_pFile)
fclose(m_pFile);
m_pFile = NULL;
}
//*********************************************************************************************
int64_t CFile::Seek(int64_t iFilePosition, int iWhence)
{
if (!m_pFile)
return -1;
return fseeko64(m_pFile, iFilePosition, iWhence);;
}
//*********************************************************************************************
int64_t CFile::GetLength()
{
return m_iLength;
}
//*********************************************************************************************
int64_t CFile::GetPosition()
{
if (!m_pFile)
return -1;
return ftello64(m_pFile);
}
//*********************************************************************************************
int CFile::Write(const void* lpBuf, int64_t uiBufSize)
{
return -1;
}
int CFile::IoControl(EIoControl request, void* param)
{
if(request == IOCTRL_SEEK_POSSIBLE)
return 1;
return -1;
}

83
File.h Normal file
View file

@ -0,0 +1,83 @@
/*
* XBMC Media Center
* Copyright (c) 2002 Frodo
* Portions Copyright (c) by the authors of ffmpeg and xvid
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
// File.h: interface for the CFile class.
//
//////////////////////////////////////////////////////////////////////
#if !defined(AFX_FILE_H__A7ED6320_C362_49CB_8925_6C6C8CAE7B78__INCLUDED_)
#define AFX_FILE_H__A7ED6320_C362_49CB_8925_6C6C8CAE7B78__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#define FFMPEG_FILE_BUFFER_SIZE 32768
namespace XFILE
{
/* indicate that caller can handle truncated reads, where function returns before entire buffer has been filled */
#define READ_TRUNCATED 0x01
/* indicate that that caller support read in the minimum defined chunk size, this disables internal cache then */
#define READ_CHUNKED 0x02
/* use cache to access this file */
#define READ_CACHED 0x04
/* open without caching. regardless to file type. */
#define READ_NO_CACHE 0x08
/* calcuate bitrate for file while reading */
#define READ_BITRATE 0x10
typedef enum {
IOCTRL_NATIVE = 1, /**< SNativeIoControl structure, containing what should be passed to native ioctrl */
IOCTRL_SEEK_POSSIBLE = 2, /**< return 0 if known not to work, 1 if it should work */
IOCTRL_CACHE_STATUS = 3, /**< SCacheStatus structure */
IOCTRL_CACHE_SETRATE = 4, /**< unsigned int with with speed limit for caching in bytes per second */
} EIoControl;
class CFile
{
public:
CFile();
~CFile();
bool Open(const CStdString& strFileName, unsigned int flags = 0);
bool OpenForWrite(const CStdString& strFileName, bool bOverWrite);
unsigned int Read(void* lpBuf, int64_t uiBufSize);
int Write(const void* lpBuf, int64_t uiBufSize);
int64_t Seek(int64_t iFilePosition, int iWhence = SEEK_SET);
int64_t GetPosition();
int64_t GetLength();
void Close();
static bool Exists(const CStdString& strFileName, bool bUseCache = true);
int GetChunkSize() { return 6144 /*FFMPEG_FILE_BUFFER_SIZE*/; };
int IoControl(EIoControl request, void* param);
private:
unsigned int m_flags;
FILE *m_pFile;
int64_t m_iLength;
};
};
#endif // !defined(AFX_FILE_H__A7ED6320_C362_49CB_8925_6C6C8CAE7B78__INCLUDED_)

86
IAudioRenderer.h Normal file
View file

@ -0,0 +1,86 @@
/*
* XBMC Media Center
* Copyright (c) 2002 d7o3g4q and RUNTiME
* Portions Copyright (c) by the authors of ffmpeg and xvid
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
// AsyncAudioRenderer.h: interface for the CAsyncDirectSound class.
//
//////////////////////////////////////////////////////////////////////
#if !defined(AFX_IAUDIORENDERER_H__B590A94D_D15E_43A6_A41D_527BD441B5F5__INCLUDED_)
#define AFX_IAUDIORENDERER_H__B590A94D_D15E_43A6_A41D_527BD441B5F5__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#include "utils/StdString.h"
#include "cores/IAudioCallback.h"
#include "utils/PCMRemap.h"
extern void RegisterAudioCallback(IAudioCallback* pCallback);
extern void UnRegisterAudioCallback();
typedef std::pair<CStdString, CStdString> AudioSink;
typedef std::vector<AudioSink> AudioSinkList;
class IAudioRenderer
{
public:
enum EEncoded {
ENCODED_NONE = 0,
ENCODED_IEC61937_AC3,
ENCODED_IEC61937_EAC3,
ENCODED_IEC61937_DTS,
ENCODED_IEC61937_MPEG,
ENCODED_IEC61937_UNKNOWN,
};
IAudioRenderer() {};
virtual ~IAudioRenderer() {};
virtual bool Initialize(IAudioCallback* pCallback, const CStdString& device, int iChannels, enum PCMChannels *channelMap, unsigned int uiSamplesPerSec, unsigned int uiBitsPerSample, bool bResample, bool bIsMusic=false, EEncoded encoded = ENCODED_NONE) = 0;
virtual void UnRegisterAudioCallback() = 0;
virtual void RegisterAudioCallback(IAudioCallback* pCallback) = 0;
virtual float GetDelay() = 0;
virtual float GetCacheTime() = 0;
virtual float GetCacheTotal() { return 1.0f; }
virtual unsigned int AddPackets(const void* data, unsigned int len) = 0;
virtual bool IsResampling() { return false;};
virtual unsigned int GetSpace() = 0;
virtual bool Deinitialize() = 0;
virtual bool Pause() = 0;
virtual bool Stop() = 0;
virtual bool Resume() = 0;
virtual unsigned int GetChunkLen() = 0;
virtual long GetCurrentVolume() const = 0;
virtual void Mute(bool bMute) = 0;
virtual bool SetCurrentVolume(long nVolume) = 0;
virtual void SetDynamicRangeCompression(long drc) {};
virtual float GetCurrentAttenuation() { return m_remap.GetCurrentAttenuation(); }
virtual int SetPlaySpeed(int iSpeed) = 0;
virtual void WaitCompletion() = 0;
virtual void SwitchChannels(int iAudioStream, bool bAudioOnAllSpeakers) = 0;
protected:
CPCMRemap m_remap;
private:
};
#endif // !defined(AFX_IAUDIORENDERER_H__B590A94D_D15E_43A6_A41D_527BD441B5F5__INCLUDED_)

65
Makefile Normal file
View file

@ -0,0 +1,65 @@
include Makefile.include
CFLAGS+=-DSTANDALONE -D__STDC_CONSTANT_MACROS -D__STDC_LIMIT_MACROS -DTARGET_POSIX -D_LINUX -fPIC -DPIC -D_REENTRANT -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CMAKE_CONFIG -D__VIDEOCORE4__ -U_FORTIFY_SOURCE -Wall -mfpu=vfp -mfloat-abi=softfp -mno-apcs-stack-check -DHAVE_OMXLIB -DUSE_EXTERNAL_FFMPEG -DHAVE_LIBAVCODEC_AVCODEC_H -DHAVE_LIBAVUTIL_MEM_H -DHAVE_LIBAVUTIL_AVUTIL_H -DHAVE_LIBAVFORMAT_AVFORMAT_H -DHAVE_LIBAVFILTER_AVFILTER_H -DOMX -DOMX_SKIP64BIT -ftree-vectorize -pipe -DUSE_EXTERNAL_OMX -DHAVE_PLATFORM_RASPBERRY_PI -DUSE_EXTERNAL_LIBBCM_HOST -Wno-psabi -I$(SDKSTAGE)/opt/vc/include/
LDFLAGS+=-L./ -lc -lWFC -lGLESv2 -lEGL -lbcm_host -lopenmaxil -Lffmpeg_compiled/usr/local/lib/
INCLUDES+=-I./ -Ilinux -Iffmpeg_compiled/usr/local/include/
SRC=linux/XMemUtils.cpp \
utils/log.cpp \
DynamicDll.cpp \
utils/PCMRemap.cpp \
utils/RegExp.cpp \
OMXSubtitleTagSami.cpp \
OMXOverlayCodecText.cpp \
BitstreamConverter.cpp \
linux/RBP.cpp \
OMXThread.cpp \
OMXReader.cpp \
OMXStreamInfo.cpp \
OMXAudioCodecOMX.cpp \
OMXCore.cpp \
OMXVideo.cpp \
OMXAudio.cpp \
OMXClock.cpp \
File.cpp \
OMXPlayerVideo.cpp \
OMXPlayerAudio.cpp \
omxplayer.cpp \
OBJS+=$(filter %.o,$(SRC:.cpp=.o))
all: omxplayer.bin
%.o: %.cpp
@rm -f $@
$(CXX) $(CFLAGS) $(INCLUDES) -c $< -o $@ -Wno-deprecated-declarations
list_test:
$(CXX) -O3 -o list_test list_test.cpp
omxplayer.bin: $(OBJS)
$(CXX) $(LDFLAGS) -o omxplayer.bin -Wl,--whole-archive $(OBJS) -Wl,--no-whole-archive -rdynamic -lavutil -lavcodec -lavformat -lswscale -lpcre
#arm-unknown-linux-gnueabi-strip omxplayer.bin
clean:
for i in $(OBJS); do (if test -e "$$i"; then ( rm $$i ); fi ); done
@rm -f omxplayer.old.log omxplayer.log
@rm -f omxplayer.bin
@rm -rf omxplayer-dist
@rm -f omxplayer-dist.tar.gz
make -f Makefile.ffmpeg clean
ffmpeg:
@rm -rf ffmpeg
make -f Makefile.ffmpeg
make -f Makefile.ffmpeg install
dist: omxplayer.bin
mkdir -p omxplayer-dist/usr/lib/omxplayer
mkdir -p omxplayer-dist/usr/usr/bin
mkdir -p omxplayer-dist/usr/share/doc
cp omxplayer omxplayer.bin omxplayer-dist/usr/usr/bin
cp README COPYING omxplayer-dist/usr/share/doc/
cp -a ffmpeg_compiled/usr/local/lib/*.so* omxplayer-dist/usr/lib/omxplayer/
tar -czf omxplayer-dist.tar.gz omxplayer-dist

70
Makefile.ffmpeg Normal file
View file

@ -0,0 +1,70 @@
include Makefile.include
CFLAGS=-D__STDC_CONSTANT_MACROS -D__STDC_LIMIT_MACROS -DTARGET_POSIX -D_LINUX -fPIC -DPIC -D_REENTRANT -D_HAVE_SBRK -D_LARGEFILE64_SOURCE -DHAVE_CMAKE_CONFIG -DHAVE_VMCS_CONFIG -D_REENTRANT -DUSE_VCHIQ_ARM -DVCHI_BULK_ALIGN=1 -DVCHI_BULK_GRANULARITY=1 -DEGL_SERVER_DISPMANX -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D__VIDEOCORE4__ -DGRAPHICS_X_VG=1 -U_FORTIFY_SOURCE -Wall -DHAVE_OMXLIB -DUSE_EXTERNAL_FFMPEG -DHAVE_LIBAVCODEC_AVCODEC_H -DHAVE_LIBAVUTIL_MEM_H -DHAVE_LIBAVUTIL_AVUTIL_H -DHAVE_LIBAVFORMAT_AVFORMAT_H -DHAVE_LIBAVFILTER_AVFILTER_H -DOMX -DOMX_SKIP64BIT
WORK=$(PWD)
all: checkout configure compile
copy:
find ffmpeg -name '*.so*' -exec cp {} . \;
$(HOST)-strip *.so*
compile:
cd ffmpeg; \
make -j9
configure:
cd ffmpeg; \
CFLAGS="$(CFLAGS) ${INCLUDES}" \
LDFLAGS="" \
./configure \
--extra-cflags="-mfpu=vfp -mfloat-abi=softfp -mno-apcs-stack-check -mstructure-size-boundary=32 -mno-sched-prolog" \
--enable-cross-compile \
--enable-shared \
--disable-static \
--arch=arm \
--cpu=arm1176jzf-s \
--target-os=linux \
--disable-muxers \
--enable-muxer=spdif \
--enable-muxer=adts \
--disable-encoders \
--enable-encoder=ac3 \
--enable-encoder=aac \
--disable-decoder=mpeg_xvmc \
--disable-devices \
--disable-ffprobe \
--disable-ffplay \
--disable-ffserver \
--disable-ffmpeg \
--enable-shared \
--disable-doc \
--enable-postproc \
--enable-gpl \
--enable-protocol=http \
--enable-pthreads \
--disable-runtime-cpudetect \
--enable-pic \
--disable-armv5te \
--disable-neon \
--enable-armv6t2 \
--enable-armv6 \
--enable-armvfp \
--enable-hardcoded-tables \
--disable-runtime-cpudetect \
--disable-debug \
--cross-prefix=$(HOST)-
clean:
@rm -rf ffmpeg
checkout:
git clone git://git.videolan.org/ffmpeg.git ffmpeg; \
cd ffmpeg; git checkout master; git checkout 67f5650a78de2567c58dbd7545434cc6d3ef9b7e
#cd ffmpeg; git checkout master; git checkout ec09230c9a11fbac602380614b35a51ad3a8dc3a
install:
cd ffmpeg; make -j9 DESTDIR="$(WORK)/ffmpeg_compiled" install
$(HOST)-strip ffmpeg_compiled/usr/local/lib/*.so

37
Makefile.include Normal file
View file

@ -0,0 +1,37 @@
USE_BUILDROOT=1
ifeq ($(USE_BUILDROOT), 1)
BUILDROOT :=/opt/xbmc-bcm/buildroot
SDKSTAGE :=$(BUILDROOT)/output/staging
TARGETFS :=$(BUILDROOT)/output/target
TOOLCHAIN :=$(BUILDROOT)/output/host/usr/
HOST :=arm-unknown-linux-gnueabi
SYSROOT :=$(BUILDROOT)/output/host/usr/arm-unknown-linux-gnueabi/sysroot
else
BUILDROOT :=/opt/bcm-rootfs
SDKSTAGE :=/opt/bcm-rootfs
TARGETFS :=/opt/bcm-rootfs
TOOLCHAIN :=/usr/local/bcm-gcc
HOST :=bcm2708
SYSROOT :=$(TOOLCHAIN)/arm-bcm2708-linux-gnueabi/sys-root
endif
JOBS=7
CFLAGS := -isystem$(PREFIX)/include
CXXFLAGS := $(CFLAGS)
CPPFLAGS := $(CFLAGS)
LDFLAGS := -L$(BUILDROOT)/lib
LD := $(TOOLCHAIN)/bin/$(HOST)-ld --sysroot=$(SYSROOT)
CC := $(TOOLCHAIN)/bin/$(HOST)-gcc --sysroot=$(SYSROOT)
CXX := $(TOOLCHAIN)/bin/$(HOST)-g++ --sysroot=$(SYSROOT)
OBJDUMP := $(TOOLCHAIN)/bin/$(HOST)-objdump
RANLIB := $(TOOLCHAIN)/bin/$(HOST)-ranlib
STRIP := $(TOOLCHAIN)/bin/$(HOST)-strip
AR := $(TOOLCHAIN)/bin/$(HOST)-ar
CXXCP := $(CXX) -E
PATH := $(PREFIX)/bin:$(BUILDROOT)/output/host/usr/bin:$(PATH)
CFLAGS += -pipe -mfloat-abi=softfp -mcpu=arm1176jzf-s -fomit-frame-pointer -mabi=aapcs-linux -mtune=arm1176jzf-s -mfpu=vfp -Wno-psabi -mno-apcs-stack-check -O3 -mstructure-size-boundary=32 -mno-sched-prolog
LDFLAGS += -L$(SDKSTAGE)/lib -L$(SDKSTAGE)/usr/lib -L$(SDKSTAGE)/opt/vc/lib/
INCLUDES += -isystem$(SDKSTAGE)/staging/usr/include -isystem$(SDKSTAGE)/staging/opt/vc/include -isystem$(SYSROOT)/usr/include

1466
OMXAudio.cpp Normal file

File diff suppressed because it is too large Load diff

143
OMXAudio.h Normal file
View file

@ -0,0 +1,143 @@
/*
* XBMC Media Center
* Copyright (c) 2002 d7o3g4q and RUNTiME
* Portions Copyright (c) by the authors of ffmpeg and xvid
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
//////////////////////////////////////////////////////////////////////
#ifndef __OPENMAXAUDIORENDER_H__
#define __OPENMAXAUDIORENDER_H__
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
//#define STANDALONE
#ifdef STANDALONE
#include "IAudioRenderer.h"
#else
#include "../AudioRenderers/IAudioRenderer.h"
#endif
#include "cores/IAudioCallback.h"
#include "linux/PlatformDefs.h"
#include "DllAvCodec.h"
#include "DllAvUtil.h"
#include "OMXCore.h"
#include "OMXClock.h"
#include "OMXStreamInfo.h"
#include "BitstreamConverter.h"
#define AUDIO_BUFFER_SECONDS 2
#define VIS_PACKET_SIZE 3840
class COMXAudio : public IAudioRenderer
{
public:
void UnRegisterAudioCallback();
void RegisterAudioCallback(IAudioCallback* pCallback);
unsigned int GetChunkLen();
float GetDelay();
float GetCacheTime();
float GetCacheTotal();
COMXAudio();
bool Initialize(IAudioCallback* pCallback, const CStdString& device, enum PCMChannels *channelMap,
COMXStreamInfo &hints, OMXClock *clock, EEncoded bPassthrough, bool bUseHWDecode);
bool Initialize(IAudioCallback* pCallback, const CStdString& device, int iChannels, enum PCMChannels *channelMap, unsigned int uiSamplesPerSec, unsigned int uiBitsPerSample, bool bResample, bool bIsMusic=false, EEncoded bPassthrough = IAudioRenderer::ENCODED_NONE);
~COMXAudio();
unsigned int AddPackets(const void* data, unsigned int len);
unsigned int AddPackets(const void* data, unsigned int len, double dts, double pts);
unsigned int GetSpace();
bool Deinitialize();
bool Pause();
bool Stop();
bool Resume();
long GetCurrentVolume() const;
void Mute(bool bMute);
bool SetCurrentVolume(long nVolume);
void SetDynamicRangeCompression(long drc) { m_drc = drc; }
int SetPlaySpeed(int iSpeed);
void WaitCompletion();
void SwitchChannels(int iAudioStream, bool bAudioOnAllSpeakers);
void Flush();
void DoAudioWork();
static void EnumerateAudioSinks(AudioSinkList& vAudioSinks, bool passthrough);
void Process();
bool SetClock(OMXClock *clock);
void SetCodingType(CodecID codec);
bool CanHWDecode(CodecID codec);
static bool HWDecode(CodecID codec);
void PrintChannels(OMX_AUDIO_CHANNELTYPE eChannelMapping[]);
void PrintPCM(OMX_AUDIO_PARAM_PCMMODETYPE *pcm);
void PrintDDP(OMX_AUDIO_PARAM_DDPTYPE *ddparm);
void PrintDTS(OMX_AUDIO_PARAM_DTSTYPE *dtsparam);
unsigned int SyncDTS(BYTE* pData, unsigned int iSize);
unsigned int SyncAC3(BYTE* pData, unsigned int iSize);
private:
IAudioCallback* m_pCallback;
bool m_Initialized;
bool m_Pause;
bool m_CanPause;
long m_CurrentVolume;
long m_drc;
bool m_Passthrough;
bool m_HWDecode;
unsigned int m_BytesPerSec;
unsigned int m_BufferLen;
unsigned int m_ChunkLen;
unsigned int m_InputChannels;
unsigned int m_OutputChannels;
unsigned int m_BitsPerSample;
COMXCoreComponent *m_omx_clock;
OMXClock *m_av_clock;
bool m_external_clock;
bool m_setStartTime;
int m_SampleSize;
bool m_first_frame;
bool m_LostSync;
int m_SampleRate;
OMX_AUDIO_CODINGTYPE m_eEncoding;
uint8_t *m_extradata;
int m_extrasize;
// stuff for visualisation
unsigned int m_visBufferLength;
double m_last_pts;
short m_visBuffer[VIS_PACKET_SIZE+2];
OMX_AUDIO_PARAM_PCMMODETYPE m_pcm_output;
OMX_AUDIO_PARAM_PCMMODETYPE m_pcm_input;
OMX_AUDIO_PARAM_DTSTYPE m_dtsParam;
WAVEFORMATEXTENSIBLE m_wave_header;
protected:
COMXCoreComponent m_omx_render;
COMXCoreComponent m_omx_mixer;
COMXCoreComponent m_omx_decoder;
COMXCoreTunel m_omx_tunnel_clock;
COMXCoreTunel m_omx_tunnel_mixer;
COMXCoreTunel m_omx_tunnel_decoder;
DllAvUtil m_dllAvUtil;
};
#endif

351
OMXAudioCodecOMX.cpp Normal file
View file

@ -0,0 +1,351 @@
/*
* Copyright (C) 2005-2008 Team XBMC
* http://www.xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with XBMC; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#include "OMXAudioCodecOMX.h"
#ifdef _LINUX
#include "XMemUtils.h"
#endif
#include "utils/log.h"
#define MAX_AUDIO_FRAME_SIZE (AVCODEC_MAX_AUDIO_FRAME_SIZE*1.5)
COMXAudioCodecOMX::COMXAudioCodecOMX()
{
m_iBufferSize1 = 0;
m_pBuffer1 = (BYTE*)_aligned_malloc(MAX_AUDIO_FRAME_SIZE + FF_INPUT_BUFFER_PADDING_SIZE, 16);
memset(m_pBuffer1, 0, MAX_AUDIO_FRAME_SIZE + FF_INPUT_BUFFER_PADDING_SIZE);
m_iBufferSize2 = 0;
m_pBuffer2 = (BYTE*)_aligned_malloc(MAX_AUDIO_FRAME_SIZE + FF_INPUT_BUFFER_PADDING_SIZE, 16);
memset(m_pBuffer2, 0, MAX_AUDIO_FRAME_SIZE + FF_INPUT_BUFFER_PADDING_SIZE);
m_iBuffered = 0;
m_pCodecContext = NULL;
m_pConvert = NULL;
m_bOpenedCodec = false;
m_channelMap[0] = PCM_INVALID;
m_channels = 0;
m_layout = 0;
}
COMXAudioCodecOMX::~COMXAudioCodecOMX()
{
_aligned_free(m_pBuffer1);
_aligned_free(m_pBuffer2);
Dispose();
}
bool COMXAudioCodecOMX::Open(COMXStreamInfo &hints)
{
AVCodec* pCodec;
m_bOpenedCodec = false;
if (!m_dllAvCore.Load() || !m_dllAvUtil.Load() || !m_dllAvCodec.Load())
return false;
m_dllAvCodec.avcodec_register_all();
m_pCodecContext = m_dllAvCodec.avcodec_alloc_context();
m_dllAvCodec.avcodec_get_context_defaults(m_pCodecContext);
pCodec = m_dllAvCodec.avcodec_find_decoder(hints.codec);
if (!pCodec)
{
CLog::Log(LOGDEBUG,"COMXAudioCodecOMX::Open() Unable to find codec %d", hints.codec);
return false;
}
m_pCodecContext->debug_mv = 0;
m_pCodecContext->debug = 0;
m_pCodecContext->workaround_bugs = 1;
if (pCodec->capabilities & CODEC_CAP_TRUNCATED)
m_pCodecContext->flags |= CODEC_FLAG_TRUNCATED;
m_channels = 0;
m_pCodecContext->channels = hints.channels;
m_pCodecContext->sample_rate = hints.samplerate;
m_pCodecContext->block_align = hints.blockalign;
m_pCodecContext->bit_rate = hints.bitrate;
m_pCodecContext->bits_per_coded_sample = hints.bitspersample;
if(m_pCodecContext->bits_per_coded_sample == 0)
m_pCodecContext->bits_per_coded_sample = 16;
if( hints.extradata && hints.extrasize > 0 )
{
m_pCodecContext->extradata_size = hints.extrasize;
m_pCodecContext->extradata = (uint8_t*)m_dllAvUtil.av_mallocz(hints.extrasize + FF_INPUT_BUFFER_PADDING_SIZE);
memcpy(m_pCodecContext->extradata, hints.extradata, hints.extrasize);
}
if (m_dllAvCodec.avcodec_open(m_pCodecContext, pCodec) < 0)
{
CLog::Log(LOGDEBUG,"COMXAudioCodecOMX::Open() Unable to open codec");
Dispose();
return false;
}
m_bOpenedCodec = true;
m_iSampleFormat = AV_SAMPLE_FMT_NONE;
return true;
}
void COMXAudioCodecOMX::Dispose()
{
if (m_pConvert)
{
m_dllAvCodec.av_audio_convert_free(m_pConvert);
m_pConvert = NULL;
}
if (m_pCodecContext)
{
if (m_bOpenedCodec) m_dllAvCodec.avcodec_close(m_pCodecContext);
m_bOpenedCodec = false;
m_dllAvUtil.av_free(m_pCodecContext);
m_pCodecContext = NULL;
}
m_dllAvCodec.Unload();
m_dllAvUtil.Unload();
m_iBufferSize1 = 0;
m_iBufferSize2 = 0;
m_iBuffered = 0;
}
int COMXAudioCodecOMX::Decode(BYTE* pData, int iSize)
{
int iBytesUsed;
if (!m_pCodecContext) return -1;
if (iSize < 1) return iSize;
m_iBufferSize1 = AVCODEC_MAX_AUDIO_FRAME_SIZE;
m_iBufferSize2 = 0;
AVPacket avpkt;
m_dllAvCodec.av_init_packet(&avpkt);
avpkt.data = pData;
avpkt.size = iSize;
iBytesUsed = m_dllAvCodec.avcodec_decode_audio3( m_pCodecContext
, (int16_t*)m_pBuffer1
, &m_iBufferSize1
, &avpkt);
/* some codecs will attempt to consume more data than what we gave */
if (iBytesUsed > iSize)
{
CLog::Log(LOGWARNING, "COMXAudioCodecOMX::Decode - decoder attempted to consume more data than given");
iBytesUsed = iSize;
}
if(m_iBufferSize1 == 0 && iBytesUsed >= 0)
m_iBuffered += iBytesUsed;
else
m_iBuffered = 0;
if(m_pCodecContext->sample_fmt != AV_SAMPLE_FMT_S16 && m_iBufferSize1 > 0)
{
if(m_pConvert && m_pCodecContext->sample_fmt != m_iSampleFormat)
{
m_dllAvCodec.av_audio_convert_free(m_pConvert);
m_pConvert = NULL;
}
if(!m_pConvert)
{
m_iSampleFormat = m_pCodecContext->sample_fmt;
m_pConvert = m_dllAvCodec.av_audio_convert_alloc(AV_SAMPLE_FMT_S16, 1, m_pCodecContext->sample_fmt, 1, NULL, 0);
}
if(!m_pConvert)
{
CLog::Log(LOGERROR, "COMXAudioCodecOMX::Decode - Unable to convert %d to AV_SAMPLE_FMT_S16", m_pCodecContext->sample_fmt);
m_iBufferSize1 = 0;
m_iBufferSize2 = 0;
return iBytesUsed;
}
const void *ibuf[6] = { m_pBuffer1 };
void *obuf[6] = { m_pBuffer2 };
int istr[6] = { m_dllAvCore.av_get_bits_per_sample_fmt(m_pCodecContext->sample_fmt)/8 };
int ostr[6] = { 2 };
int len = m_iBufferSize1 / istr[0];
if(m_dllAvCodec.av_audio_convert(m_pConvert, obuf, ostr, ibuf, istr, len) < 0)
{
CLog::Log(LOGERROR, "COMXAudioCodecOMX::Decode - Unable to convert %d to AV_SAMPLE_FMT_S16", (int)m_pCodecContext->sample_fmt);
m_iBufferSize1 = 0;
m_iBufferSize2 = 0;
return iBytesUsed;
}
m_iBufferSize1 = 0;
m_iBufferSize2 = len * ostr[0];
}
return iBytesUsed;
}
int COMXAudioCodecOMX::GetData(BYTE** dst)
{
// TODO: Use a third buffer and decide which is our source data
if(m_pCodecContext->channels == 6 && m_iBufferSize1)
{
int16_t *pDst = (int16_t *)m_pBuffer2;
int16_t *pSrc = (int16_t *)m_pBuffer1;
//printf("\ncopy_chunk_len %d, omx_chunk_len %d\n", copy_chunk_len, omx_chunk_len);
memset(m_pBuffer2, 0, MAX_AUDIO_FRAME_SIZE + FF_INPUT_BUFFER_PADDING_SIZE);
m_iBufferSize2 = 0;
int size = m_iBufferSize1 / 2;
int gap = 8 - m_pCodecContext->channels;
int samples = 0;
for(int i = 0; i < size; pDst++, pSrc++, i++, samples++)
{
if( (i%m_pCodecContext->channels) == 0)
{
pDst += gap;
samples += gap;
}
*pDst = *pSrc;
}
m_iBufferSize2 = samples * 2;
*dst = m_pBuffer2;
return m_iBufferSize2;
}
if(m_iBufferSize1)
{
*dst = m_pBuffer1;
return m_iBufferSize1;
}
if(m_iBufferSize2)
{
*dst = m_pBuffer2;
return m_iBufferSize2;
}
return 0;
}
void COMXAudioCodecOMX::Reset()
{
if (m_pCodecContext) m_dllAvCodec.avcodec_flush_buffers(m_pCodecContext);
m_iBufferSize1 = 0;
m_iBufferSize2 = 0;
m_iBuffered = 0;
}
int COMXAudioCodecOMX::GetChannels()
{
return (m_pCodecContext->channels == 6) ? 8 : m_pCodecContext->channels;
}
int COMXAudioCodecOMX::GetSampleRate()
{
if (m_pCodecContext) return m_pCodecContext->sample_rate;
return 0;
}
int COMXAudioCodecOMX::GetBitsPerSample()
{
return 16;
}
int COMXAudioCodecOMX::GetBitRate()
{
if (m_pCodecContext) return m_pCodecContext->bit_rate;
return 0;
}
static unsigned count_bits(int64_t value)
{
unsigned bits = 0;
for(;value;++bits)
value &= value - 1;
return bits;
}
void COMXAudioCodecOMX::BuildChannelMap()
{
if (m_channels == m_pCodecContext->channels && m_layout == m_pCodecContext->channel_layout)
return; //nothing to do here
m_channels = m_pCodecContext->channels;
m_layout = m_pCodecContext->channel_layout;
int64_t layout;
int bits = count_bits(m_pCodecContext->channel_layout);
if (bits == m_pCodecContext->channels)
layout = m_pCodecContext->channel_layout;
else
{
CLog::Log(LOGINFO, "COMXAudioCodecOMX::GetChannelMap - FFmpeg reported %d channels, but the layout contains %d ignoring", m_pCodecContext->channels, bits);
layout = m_dllAvCodec.avcodec_guess_channel_layout(m_pCodecContext->channels, m_pCodecContext->codec_id, NULL);
}
int index = 0;
if (layout & AV_CH_FRONT_LEFT ) m_channelMap[index++] = PCM_FRONT_LEFT ;
if (layout & AV_CH_FRONT_RIGHT ) m_channelMap[index++] = PCM_FRONT_RIGHT ;
if (layout & AV_CH_FRONT_CENTER ) m_channelMap[index++] = PCM_FRONT_CENTER ;
if (layout & AV_CH_LOW_FREQUENCY ) m_channelMap[index++] = PCM_LOW_FREQUENCY ;
if (layout & AV_CH_BACK_LEFT ) m_channelMap[index++] = PCM_BACK_LEFT ;
if (layout & AV_CH_BACK_RIGHT ) m_channelMap[index++] = PCM_BACK_RIGHT ;
if (layout & AV_CH_FRONT_LEFT_OF_CENTER ) m_channelMap[index++] = PCM_FRONT_LEFT_OF_CENTER ;
if (layout & AV_CH_FRONT_RIGHT_OF_CENTER) m_channelMap[index++] = PCM_FRONT_RIGHT_OF_CENTER;
if (layout & AV_CH_BACK_CENTER ) m_channelMap[index++] = PCM_BACK_CENTER ;
if (layout & AV_CH_SIDE_LEFT ) m_channelMap[index++] = PCM_SIDE_LEFT ;
if (layout & AV_CH_SIDE_RIGHT ) m_channelMap[index++] = PCM_SIDE_RIGHT ;
if (layout & AV_CH_TOP_CENTER ) m_channelMap[index++] = PCM_TOP_CENTER ;
if (layout & AV_CH_TOP_FRONT_LEFT ) m_channelMap[index++] = PCM_TOP_FRONT_LEFT ;
if (layout & AV_CH_TOP_FRONT_CENTER ) m_channelMap[index++] = PCM_TOP_FRONT_CENTER ;
if (layout & AV_CH_TOP_FRONT_RIGHT ) m_channelMap[index++] = PCM_TOP_FRONT_RIGHT ;
if (layout & AV_CH_TOP_BACK_LEFT ) m_channelMap[index++] = PCM_TOP_BACK_LEFT ;
if (layout & AV_CH_TOP_BACK_CENTER ) m_channelMap[index++] = PCM_TOP_BACK_CENTER ;
if (layout & AV_CH_TOP_BACK_RIGHT ) m_channelMap[index++] = PCM_TOP_BACK_RIGHT ;
//terminate the channel map
m_channelMap[index] = PCM_INVALID;
if(m_pCodecContext->channels == 6)
{
m_channelMap[6] = PCM_INVALID;
m_channelMap[7] = PCM_INVALID;
m_channelMap[8] = PCM_INVALID;
}
}
enum PCMChannels* COMXAudioCodecOMX::GetChannelMap()
{
BuildChannelMap();
if (m_channelMap[0] == PCM_INVALID)
return NULL;
return m_channelMap;
}

74
OMXAudioCodecOMX.h Normal file
View file

@ -0,0 +1,74 @@
#pragma once
/*
* Copyright (C) 2005-2008 Team XBMC
* http://www.xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with XBMC; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#include "DllAvCodec.h"
#include "DllAvCore.h"
#include "DllAvFormat.h"
#include "DllAvUtil.h"
#include "OMXStreamInfo.h"
#include "utils/PCMRemap.h"
#include "linux/PlatformDefs.h"
class COMXAudioCodecOMX
{
public:
COMXAudioCodecOMX();
~COMXAudioCodecOMX();
bool Open(COMXStreamInfo &hints);
void Dispose();
int Decode(BYTE* pData, int iSize);
int GetData(BYTE** dst);
void Reset();
int GetChannels();
enum PCMChannels *GetChannelMap();
int GetSampleRate();
int GetBitsPerSample();
const char* GetName() { return "FFmpeg"; }
int GetBufferSize() { return m_iBuffered; }
int GetBitRate();
protected:
AVCodecContext* m_pCodecContext;
AVAudioConvert* m_pConvert;;
enum AVSampleFormat m_iSampleFormat;
enum PCMChannels m_channelMap[PCM_MAX_CH + 1];
BYTE *m_pBuffer1;
int m_iBufferSize1;
BYTE *m_pBuffer2;
int m_iBufferSize2;
bool m_bOpenedCodec;
int m_iBuffered;
int m_channels;
uint64_t m_layout;
DllAvCodec m_dllAvCodec;
DllAvCore m_dllAvCore;
DllAvUtil m_dllAvUtil;
void BuildChannelMap();
};

688
OMXClock.cpp Normal file
View file

@ -0,0 +1,688 @@
/*
* Copyright (C) 2005-2008 Team XBMC
* http://www.xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with XBMC; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#if (defined HAVE_CONFIG_H) && (!defined WIN32)
#include "config.h"
#elif defined(_WIN32)
#include "system.h"
#endif
#include "OMXClock.h"
int64_t OMXClock::m_systemOffset;
int64_t OMXClock::m_systemFrequency;
bool OMXClock::m_ismasterclock;
OMXClock::OMXClock()
{
m_dllAvFormat.Load();
m_video_clock = DVD_NOPTS_VALUE;
m_audio_clock = DVD_NOPTS_VALUE;
m_has_video = false;
m_has_audio = false;
m_play_speed = 1;
m_pause = false;
m_iCurrentPts = DVD_NOPTS_VALUE;
m_systemFrequency = CurrentHostFrequency();
m_systemUsed = m_systemFrequency;
m_pauseClock = 0;
m_bReset = true;
m_iDisc = 0;
m_maxspeedadjust = 0.0;
m_speedadjust = false;
m_ismasterclock = true;
m_ClockOffset = 0;
m_fps = 25.0f;
pthread_mutex_init(&m_lock, NULL);
CheckSystemClock();
OMXReset();
}
OMXClock::~OMXClock()
{
Deinitialize();
m_dllAvFormat.Unload();
pthread_mutex_destroy(&m_lock);
}
void OMXClock::Lock()
{
pthread_mutex_lock(&m_lock);
}
void OMXClock::UnLock()
{
pthread_mutex_unlock(&m_lock);
}
double OMXClock::SystemToAbsolute(int64_t system)
{
return DVD_TIME_BASE * (double)(system - m_systemOffset) / m_systemFrequency;
}
double OMXClock::SystemToPlaying(int64_t system)
{
int64_t current;
if (m_bReset)
{
m_startClock = system;
m_systemUsed = m_systemFrequency;
m_pauseClock = 0;
m_iDisc = 0;
m_bReset = false;
}
if (m_pauseClock)
current = m_pauseClock;
else
current = system;
return DVD_TIME_BASE * (double)(current - m_startClock) / m_systemUsed + m_iDisc;
}
int64_t OMXClock::GetFrequency()
{
return m_systemFrequency;
}
int64_t OMXClock::Wait(int64_t Target)
{
int64_t Now;
int SleepTime;
int64_t ClockOffset = m_ClockOffset;
Now = CurrentHostCounter();
//sleep until the timestamp has passed
SleepTime = (int)((Target - (Now + ClockOffset)) * 1000 / m_systemFrequency);
if (SleepTime > 0)
OMXSleep(SleepTime);
Now = CurrentHostCounter();
return Now;
}
double OMXClock::WaitAbsoluteClock(double target)
{
Lock();
int64_t systemtarget, freq, offset;
freq = m_systemFrequency;
offset = m_systemOffset;
UnLock();
systemtarget = (int64_t)(target / DVD_TIME_BASE * (double)freq);
systemtarget += offset;
systemtarget = Wait(systemtarget);
systemtarget -= offset;
return (double)systemtarget / freq * DVD_TIME_BASE;
}
// Returns the current absolute clock in units of DVD_TIME_BASE (usually microseconds).
double OMXClock::GetAbsoluteClock(bool interpolated /*= true*/)
{
Lock();
CheckSystemClock();
double current = GetTime();
UnLock();
return SystemToAbsolute(current);
}
int64_t OMXClock::GetTime(bool interpolated)
{
return CurrentHostCounter() + m_ClockOffset;
}
void OMXClock::CheckSystemClock()
{
if(!m_systemFrequency)
m_systemFrequency = GetFrequency();
if(!m_systemOffset)
m_systemOffset = GetTime();
}
double OMXClock::GetClock(bool interpolated /*= true*/)
{
Lock();
double clock = GetTime(interpolated);
UnLock();
return SystemToPlaying(clock);
}
double OMXClock::GetClock(double& absolute, bool interpolated /*= true*/)
{
int64_t current = GetTime(interpolated);
Lock();
CheckSystemClock();
absolute = SystemToAbsolute(current);
UnLock();
return SystemToPlaying(current);
}
void OMXClock::SetSpeed(int iSpeed)
{
// this will sometimes be a little bit of due to rounding errors, ie clock might jump abit when changing speed
Lock();
if(iSpeed == DVD_PLAYSPEED_PAUSE)
{
if(!m_pauseClock)
m_pauseClock = GetTime();
UnLock();
return;
}
int64_t current;
int64_t newfreq = m_systemFrequency * DVD_PLAYSPEED_NORMAL / iSpeed;
current = GetTime();
if( m_pauseClock )
{
m_startClock += current - m_pauseClock;
m_pauseClock = 0;
}
m_startClock = current - (int64_t)((double)(current - m_startClock) * newfreq / m_systemUsed);
m_systemUsed = newfreq;
UnLock();
}
void OMXClock::Discontinuity(double currentPts)
{
Lock();
m_startClock = GetTime();
if(m_pauseClock)
m_pauseClock = m_startClock;
m_iDisc = currentPts;
m_bReset = false;
UnLock();
}
void OMXClock::Pause()
{
Lock();
if(!m_pauseClock)
m_pauseClock = GetTime();
UnLock();
}
void OMXClock::Resume()
{
Lock();
if( m_pauseClock )
{
int64_t current;
current = GetTime();
m_startClock += current - m_pauseClock;
m_pauseClock = 0;
}
UnLock();
}
bool OMXClock::SetMaxSpeedAdjust(double speed)
{
Lock();
m_maxspeedadjust = speed;
UnLock();
return m_speedadjust;
}
//returns the refreshrate if the videoreferenceclock is running, -1 otherwise
int OMXClock::UpdateFramerate(double fps, double* interval /*= NULL*/)
{
//sent with fps of 0 means we are not playing video
if(fps == 0.0)
{
Lock();
m_speedadjust = false;
UnLock();
return -1;
}
return -1;
}
bool OMXClock::OMXReset()
{
m_iCurrentPts = DVD_NOPTS_VALUE;
m_video_clock = DVD_NOPTS_VALUE;
m_audio_clock = DVD_NOPTS_VALUE;
if(m_omx_clock.GetComponent() != NULL)
{
OMX_ERRORTYPE omx_err = OMX_ErrorNone;
OMX_TIME_CONFIG_CLOCKSTATETYPE clock;
OMX_INIT_STRUCTURE(clock);
OMXStop();
clock.eState = OMX_TIME_ClockStateWaitingForStartTime;
if(m_has_audio)
{
clock.nWaitMask |= OMX_CLOCKPORT0;
}
if(m_has_video)
{
clock.nWaitMask |= OMX_CLOCKPORT1;
clock.nWaitMask |= OMX_CLOCKPORT2;
}
omx_err = OMX_SetConfig(m_omx_clock.GetComponent(), OMX_IndexConfigTimeClockState, &clock);
if(omx_err != OMX_ErrorNone)
{
CLog::Log(LOGERROR, "OMXClock::Reset error setting OMX_IndexConfigTimeClockState\n");
return false;
}
OMXStart();
}
return true;
}
bool OMXClock::OMXInitialize(bool has_video, bool has_audio)
{
OMX_ERRORTYPE omx_err = OMX_ErrorNone;
CStdString componentName = "";
m_has_video = has_video;
m_has_audio = has_audio;
componentName = "OMX.broadcom.clock";
if(!m_omx_clock.Initialize((const CStdString)componentName, OMX_IndexParamOtherInit))
return false;
OMX_TIME_CONFIG_CLOCKSTATETYPE clock;
OMX_INIT_STRUCTURE(clock);
clock.eState = OMX_TIME_ClockStateWaitingForStartTime;
if(m_has_audio)
{
clock.nWaitMask |= OMX_CLOCKPORT0;
}
if(m_has_video)
{
clock.nWaitMask |= OMX_CLOCKPORT1;
clock.nWaitMask |= OMX_CLOCKPORT2;
}
omx_err = OMX_SetConfig(m_omx_clock.GetComponent(), OMX_IndexConfigTimeClockState, &clock);
if(omx_err != OMX_ErrorNone)
{
CLog::Log(LOGERROR, "OMXClock::Initialize error setting OMX_IndexConfigTimeClockState\n");
return false;
}
OMX_TIME_CONFIG_ACTIVEREFCLOCKTYPE refClock;
OMX_INIT_STRUCTURE(refClock);
if(m_has_audio)
refClock.eClock = OMX_TIME_RefClockAudio;
else
refClock.eClock = OMX_TIME_RefClockVideo;
omx_err = OMX_SetConfig(m_omx_clock.GetComponent(), OMX_IndexConfigTimeActiveRefClock, &refClock);
if(omx_err != OMX_ErrorNone)
{
CLog::Log(LOGERROR, "OMXClock::Initialize error setting OMX_IndexConfigTimeCurrentAudioReference\n");
return false;
}
return true;
}
void OMXClock::Deinitialize()
{
m_omx_clock.Deinitialize();
}
bool OMXClock::OMXStatePause()
{
if(m_omx_clock.GetComponent() == NULL)
return false;
if(m_omx_clock.GetState() != OMX_StatePause)
{
OMX_ERRORTYPE omx_err = OMX_ErrorNone;
omx_err = m_omx_clock.SetStateForComponent(OMX_StatePause);
if (omx_err != OMX_ErrorNone)
{
CLog::Log(LOGERROR, "OMXClock::StatePause m_omx_clock.SetStateForComponent\n");
return false;
}
}
return true;
}
bool OMXClock::OMXStateExecute()
{
if(m_omx_clock.GetComponent() == NULL)
return false;
if(m_omx_clock.GetState() != OMX_StateExecuting)
{
OMX_ERRORTYPE omx_err = OMX_ErrorNone;
omx_err = m_omx_clock.SetStateForComponent(OMX_StateExecuting);
if (omx_err != OMX_ErrorNone)
{
CLog::Log(LOGERROR, "OMXClock::StateExecute m_omx_clock.SetStateForComponent\n");
return false;
}
}
return true;
}
void OMXClock::OMXStateIdle()
{
if(m_omx_clock.GetComponent() == NULL)
return;
if(m_omx_clock.GetState() == OMX_StateExecuting)
m_omx_clock.SetStateForComponent(OMX_StatePause);
if(m_omx_clock.GetState() != OMX_StateIdle)
m_omx_clock.SetStateForComponent(OMX_StateIdle);
}
COMXCoreComponent *OMXClock::GetOMXClock()
{
if(!m_omx_clock.GetComponent())
return NULL;
return &m_omx_clock;
}
bool OMXClock::OMXStop()
{
if(m_omx_clock.GetComponent() == NULL)
{
return false;
}
OMX_ERRORTYPE omx_err = OMX_ErrorNone;
OMX_TIME_CONFIG_CLOCKSTATETYPE clock;
OMX_INIT_STRUCTURE(clock);
clock.eState = OMX_TIME_ClockStateStopped;
omx_err = OMX_SetConfig(m_omx_clock.GetComponent(), OMX_IndexConfigTimeClockState, &clock);
if(omx_err != OMX_ErrorNone)
{
CLog::Log(LOGERROR, "OMXClock::Stop error setting OMX_IndexConfigTimeClockState\n");
return false;
}
return true;
}
bool OMXClock::OMXStart()
{
if(m_omx_clock.GetComponent() == NULL)
{
return false;
}
OMX_ERRORTYPE omx_err = OMX_ErrorNone;
OMX_TIME_CONFIG_CLOCKSTATETYPE clock;
OMX_INIT_STRUCTURE(clock);
clock.eState = OMX_TIME_ClockStateRunning;
omx_err = OMX_SetConfig(m_omx_clock.GetComponent(), OMX_IndexConfigTimeClockState, &clock);
if(omx_err != OMX_ErrorNone)
{
CLog::Log(LOGERROR, "OMXClock::Start error setting OMX_IndexConfigTimeClockState\n");
return false;
}
return true;
}
bool OMXClock::OMXPause()
{
if(m_omx_clock.GetComponent() == NULL)
{
return false;
}
if(m_pause)
return true;
OMX_ERRORTYPE omx_err = OMX_ErrorNone;
OMX_TIME_CONFIG_SCALETYPE scaleType;
OMX_INIT_STRUCTURE(scaleType);
scaleType.xScale = 0; // pause
omx_err = OMX_SetConfig(m_omx_clock.GetComponent(), OMX_IndexConfigTimeScale, &scaleType);
if(omx_err != OMX_ErrorNone)
{
CLog::Log(LOGERROR, "OMXClock::Pause error setting OMX_IndexConfigTimeClockState\n");
return false;
}
m_pause = true;
return true;
}
bool OMXClock::OMXResume()
{
if(m_omx_clock.GetComponent() == NULL)
{
return false;
}
if(!m_pause)
return true;
OMX_ERRORTYPE omx_err = OMX_ErrorNone;
OMX_TIME_CONFIG_SCALETYPE scaleType;
OMX_INIT_STRUCTURE(scaleType);
scaleType.xScale = (1<<16); // normal speed
omx_err = OMX_SetConfig(m_omx_clock.GetComponent(), OMX_IndexConfigTimeScale, &scaleType);
if(omx_err != OMX_ErrorNone)
{
CLog::Log(LOGERROR, "OMXClock::Resume error setting OMX_IndexConfigTimeClockState\n");
return false;
}
m_pause = false;
return true;
}
bool OMXClock::OMXWaitStart(double pts)
{
if(m_omx_clock.GetComponent() == NULL)
return false;
OMX_ERRORTYPE omx_err = OMX_ErrorNone;
OMX_TIME_CONFIG_CLOCKSTATETYPE clock;
OMX_INIT_STRUCTURE(clock);
if(pts == DVD_NOPTS_VALUE)
pts = 0;
clock.nStartTime = ToOMXTime((uint64_t)pts);
if(pts == DVD_NOPTS_VALUE)
{
clock.eState = OMX_TIME_ClockStateRunning;
clock.nWaitMask = 0;
}
else
{
clock.eState = OMX_TIME_ClockStateWaitingForStartTime;
if(m_has_audio)
{
clock.nWaitMask |= OMX_CLOCKPORT0;
}
if(m_has_video)
{
clock.nWaitMask |= OMX_CLOCKPORT1;
clock.nWaitMask |= OMX_CLOCKPORT2;
}
}
omx_err = OMX_SetConfig(m_omx_clock.GetComponent(), OMX_IndexConfigTimeClockState, &clock);
if(omx_err != OMX_ErrorNone)
{
CLog::Log(LOGERROR, "OMXClock::Initialize error setting OMX_IndexConfigTimeClockState\n");
return false;
}
return true;
}
bool OMXClock::OMXSpeed(int speed)
{
if(m_omx_clock.GetComponent() == NULL)
return false;
OMX_ERRORTYPE omx_err = OMX_ErrorNone;
OMX_TIME_CONFIG_SCALETYPE scaleType;
OMX_INIT_STRUCTURE(scaleType);
scaleType.xScale = (speed << 16);
m_play_speed = speed;
omx_err = OMX_SetConfig(m_omx_clock.GetComponent(), OMX_IndexConfigTimeScale, &scaleType);
if(omx_err != OMX_ErrorNone)
{
CLog::Log(LOGERROR, "OMXClock::Speed error setting OMX_IndexConfigTimeClockState\n");
return false;
}
return true;
}
void OMXClock::AddTimespecs(struct timespec &time, long millisecs)
{
time.tv_sec += millisecs / 1000;
time.tv_nsec += (millisecs % 1000) * 1000000;
if (time.tv_nsec > 1000000000)
{
time.tv_sec += 1;
time.tv_nsec -= 1000000000;
}
}
double OMXClock::GetPTS()
{
Lock();
double pts = m_iCurrentPts;
UnLock();
return pts;
}
void OMXClock::SetPTS(double pts)
{
Lock();
m_iCurrentPts = pts;
UnLock();
};
bool OMXClock::HDMIClockSync()
{
if(m_omx_clock.GetComponent() == NULL)
return false;
OMX_ERRORTYPE omx_err = OMX_ErrorNone;
OMX_CONFIG_LATENCYTARGETTYPE latencyTarget;
OMX_INIT_STRUCTURE(latencyTarget);
latencyTarget.nPortIndex = OMX_ALL;
latencyTarget.bEnabled = OMX_TRUE;
latencyTarget.nFilter = 10;
latencyTarget.nTarget = 0;
latencyTarget.nShift = 3;
latencyTarget.nSpeedFactor = -200;
latencyTarget.nInterFactor = 100;
latencyTarget.nAdjCap = 100;
omx_err = OMX_SetConfig(m_omx_clock.GetComponent(), OMX_IndexConfigLatencyTarget, &latencyTarget);
if(omx_err != OMX_ErrorNone)
{
CLog::Log(LOGERROR, "OMXClock::Speed error setting OMX_IndexConfigLatencyTarget\n");
return false;
}
return true;
}
int64_t OMXClock::CurrentHostCounter(void)
{
struct timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
return( ((int64_t)now.tv_sec * 1000000000L) + now.tv_nsec );
}
int64_t OMXClock::CurrentHostFrequency(void)
{
return( (int64_t)1000000000L );
}
void OMXClock::AddTimeSpecNano(struct timespec &time, uint64_t nanoseconds)
{
time.tv_sec += nanoseconds / 1000000000;
time.tv_nsec += (nanoseconds % 1000000000);
if (time.tv_nsec > 1000000000)
{
time.tv_sec += 1;
time.tv_nsec -= 1000000000;
}
}
void OMXClock::OMXSleep(unsigned int dwMilliSeconds)
{
struct timespec req;
req.tv_sec = dwMilliSeconds / 1000;
req.tv_nsec = (dwMilliSeconds % 1000) * 1000000;
while ( nanosleep(&req, &req) == -1 && errno == EINTR && (req.tv_nsec > 0 || req.tv_sec > 0));
}
int OMXClock::GetRefreshRate(double* interval)
{
if(!interval)
return false;
*interval = m_fps;
return true;
}

156
OMXClock.h Normal file
View file

@ -0,0 +1,156 @@
/*
* Copyright (C) 2005-2008 Team XBMC
* http://www.xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with XBMC; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#ifndef _AVCLOCK_H_
#define _AVCLOCK_H_
#include "DllAvFormat.h"
#include "OMXCore.h"
#define AV_SYNC_THRESHOLD 0.01
#define AV_NOSYNC_THRESHOLD 10.0
#define SAMPLE_CORRECTION_PERCENT_MAX 10
#define AUDIO_DIFF_AVG_NB 20
#define DVD_TIME_BASE 1000000
#define DVD_NOPTS_VALUE (-1LL<<52) // should be possible to represent in both double and __int64
#define DVD_TIME_TO_SEC(x) ((int)((double)(x) / DVD_TIME_BASE))
#define DVD_TIME_TO_MSEC(x) ((int)((double)(x) * 1000 / DVD_TIME_BASE))
#define DVD_SEC_TO_TIME(x) ((double)(x) * DVD_TIME_BASE)
#define DVD_MSEC_TO_TIME(x) ((double)(x) * DVD_TIME_BASE / 1000)
#define DVD_PLAYSPEED_PAUSE 0 // frame stepping
#define DVD_PLAYSPEED_NORMAL 1000
#ifdef OMX_SKIP64BIT
static inline OMX_TICKS ToOMXTime(int64_t pts)
{
OMX_TICKS ticks;
ticks.nLowPart = pts;
ticks.nHighPart = pts >> 32;
return ticks;
}
static inline uint64_t FromOMXTime(OMX_TICKS ticks)
{
uint64_t pts = ticks.nLowPart | ((uint64_t)ticks.nHighPart << 32);
return pts;
}
#else
#define FromOMXTime(x) (x)
#define ToOMXTime(x) (x)
#endif
enum {
AV_SYNC_AUDIO_MASTER,
AV_SYNC_VIDEO_MASTER,
AV_SYNC_EXTERNAL_MASTER,
};
class OMXClock
{
protected:
double m_video_clock;
double m_audio_clock;
bool m_pause;
double m_iCurrentPts;
bool m_has_video;
bool m_has_audio;
int m_play_speed;
pthread_mutex_t m_lock;
void CheckSystemClock();
double SystemToAbsolute(int64_t system);
double SystemToPlaying(int64_t system);
int64_t m_systemUsed;
int64_t m_startClock;
int64_t m_pauseClock;
double m_iDisc;
bool m_bReset;
static int64_t m_systemFrequency;
static int64_t m_systemOffset;
int64_t m_ClockOffset;
double m_maxspeedadjust;
bool m_speedadjust;
static bool m_ismasterclock;
double m_fps;
private:
COMXCoreComponent m_omx_clock;
DllAvFormat m_dllAvFormat;
public:
OMXClock();
~OMXClock();
void Lock();
void UnLock();
int64_t GetFrequency();
int64_t GetTime(bool interpolated = true);
double GetAbsoluteClock(bool interpolated = true);
int64_t Wait(int64_t Target);
double WaitAbsoluteClock(double target);
double GetClock(bool interpolated = true);
double GetClock(double& absolute, bool interpolated = true);
void SetSpeed(int iSpeed);
void SetMasterClock(bool ismasterclock) { m_ismasterclock = ismasterclock; }
bool IsMasterClock() { return m_ismasterclock; }
void Discontinuity(double currentPts = 0LL);
void Reset() { m_bReset = true; }
void Pause();
void Resume();
int UpdateFramerate(double fps, double* interval = NULL);
bool SetMaxSpeedAdjust(double speed);
bool OMXReset();
bool OMXInitialize(bool has_video, bool has_audio);
void Deinitialize();
bool OMXIsPaused() { return m_pause; };
bool OMXStop();
bool OMXStart();
bool OMXPause();
bool OMXResume();
bool OMXWaitStart(double pts);
bool OMXSpeed(int speed);
int OMXPlaySpeed() { return m_play_speed; };
COMXCoreComponent *GetOMXClock();
bool OMXStatePause();
bool OMXStateExecute();
void OMXStateIdle();
double GetPTS();
void SetPTS(double pts);
static void AddTimespecs(struct timespec &time, long millisecs);
bool HDMIClockSync();
static int64_t CurrentHostCounter(void);
static int64_t CurrentHostFrequency(void);
void SetVideoClock(double video_clock) { m_video_clock = video_clock; };
void SetAudioClock(double audio_clock) { m_audio_clock = audio_clock; };
double GetVideoClock() { return m_video_clock; };
double GetAudioClock() { return m_audio_clock; };
bool HasVideo() { return m_has_video; };
bool HasAudio() { return m_has_audio; };
static void AddTimeSpecNano(struct timespec &time, uint64_t nanoseconds);
static void OMXSleep(unsigned int dwMilliSeconds);
int GetRefreshRate(double* interval = NULL);
void SetRefreshRate(double fps) { m_fps = fps; };
};
#endif

1642
OMXCore.cpp Normal file

File diff suppressed because it is too large Load diff

216
OMXCore.h Normal file
View file

@ -0,0 +1,216 @@
#pragma once
/*
* Copyright (C) 2010 Team XBMC
* http://www.xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with XBMC; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#if defined(HAVE_OMXLIB)
#include "utils/StdString.h"
#include <queue>
// TODO: should this be in configure
#ifndef OMX_SKIP64BIT
#define OMX_SKIP64BIT
#endif
#include "DllOMX.h"
#include <semaphore.h>
////////////////////////////////////////////////////////////////////////////////////////////
// debug spew defines
#if 0
#define OMX_DEBUG_VERBOSE
#define OMX_DEBUG_EVENTHANDLER
#endif
#define OMX_INIT_STRUCTURE(a) \
memset(&(a), 0, sizeof(a)); \
(a).nSize = sizeof(a); \
(a).nVersion.s.nVersionMajor = OMX_VERSION_MAJOR; \
(a).nVersion.s.nVersionMinor = OMX_VERSION_MINOR; \
(a).nVersion.s.nRevision = OMX_VERSION_REVISION; \
(a).nVersion.s.nStep = OMX_VERSION_STEP
#include "DllAvFormat.h"
#define OMX_MAX_PORTS 10
typedef struct omx_event {
OMX_EVENTTYPE eEvent;
OMX_U32 nData1;
OMX_U32 nData2;
} omx_event;
class DllLibOMXCore;
class COMXCore;
class COMXCoreComponent;
class COMXCoreTunel;
class COMXCoreClock;
class COMXCoreTunel
{
public:
COMXCoreTunel();
~COMXCoreTunel();
void Initialize(COMXCoreComponent *src_component, unsigned int src_port, COMXCoreComponent *dst_component, unsigned int dst_port);
OMX_ERRORTYPE Flush();
OMX_ERRORTYPE Deestablish(bool noWait = false);
OMX_ERRORTYPE Establish(bool portSettingsChanged);
private:
bool m_portSettingsChanged;
COMXCoreComponent *m_src_component;
COMXCoreComponent *m_dst_component;
unsigned int m_src_port;
unsigned int m_dst_port;
DllOMX *m_DllOMX;
bool m_DllOMXOpen;
};
class COMXCoreComponent
{
public:
COMXCoreComponent();
~COMXCoreComponent();
OMX_HANDLETYPE GetComponent() { return m_handle; };
unsigned int GetInputPort() { return m_input_port; };
unsigned int GetOutputPort() { return m_output_port; };
CStdString GetName() { return m_componentName; };
OMX_ERRORTYPE DisableAllPorts();
void Remove(OMX_EVENTTYPE eEvent, OMX_U32 nData1, OMX_U32 nData2);
OMX_ERRORTYPE AddEvent(OMX_EVENTTYPE eEvent, OMX_U32 nData1, OMX_U32 nData2);
//bool GotError(OMX_ERRORTYPE errorType);
OMX_ERRORTYPE WaitForEvent(OMX_EVENTTYPE event, long timeout = 300);
OMX_ERRORTYPE WaitForCommand(OMX_U32 command, OMX_U32 nData2, long timeout = 2000);
OMX_ERRORTYPE SetStateForComponent(OMX_STATETYPE state);
OMX_STATETYPE GetState();
OMX_ERRORTYPE SetParameter(OMX_INDEXTYPE paramIndex, OMX_PTR paramStruct);
OMX_ERRORTYPE GetParameter(OMX_INDEXTYPE paramIndex, OMX_PTR paramStruct);
OMX_ERRORTYPE SetConfig(OMX_INDEXTYPE configIndex, OMX_PTR configStruct);
OMX_ERRORTYPE GetConfig(OMX_INDEXTYPE configIndex, OMX_PTR configStruct);
OMX_ERRORTYPE SendCommand(OMX_COMMANDTYPE cmd, OMX_U32 cmdParam, OMX_PTR cmdParamData);
OMX_ERRORTYPE EnablePort(unsigned int port, bool wait = true);
OMX_ERRORTYPE DisablePort(unsigned int port, bool wait = true);
OMX_ERRORTYPE UseEGLImage(OMX_BUFFERHEADERTYPE** ppBufferHdr, OMX_U32 nPortIndex, OMX_PTR pAppPrivate, void* eglImage);
bool Initialize( const CStdString &component_name, OMX_INDEXTYPE index);
bool Deinitialize();
// OMXCore Decoder delegate callback routines.
static OMX_ERRORTYPE DecoderEventHandlerCallback(OMX_HANDLETYPE hComponent, OMX_PTR pAppData,
OMX_EVENTTYPE eEvent, OMX_U32 nData1, OMX_U32 nData2, OMX_PTR pEventData);
static OMX_ERRORTYPE DecoderEmptyBufferDoneCallback(
OMX_HANDLETYPE hComponent, OMX_PTR pAppData, OMX_BUFFERHEADERTYPE* pBuffer);
static OMX_ERRORTYPE DecoderFillBufferDoneCallback(
OMX_HANDLETYPE hComponent, OMX_PTR pAppData, OMX_BUFFERHEADERTYPE* pBufferHeader);
// OMXCore decoder callback routines.
OMX_ERRORTYPE DecoderEventHandler(OMX_HANDLETYPE hComponent, OMX_PTR pAppData,
OMX_EVENTTYPE eEvent, OMX_U32 nData1, OMX_U32 nData2, OMX_PTR pEventData);
OMX_ERRORTYPE DecoderEmptyBufferDone(
OMX_HANDLETYPE hComponent, OMX_PTR pAppData, OMX_BUFFERHEADERTYPE* pBuffer);
OMX_ERRORTYPE DecoderFillBufferDone(
OMX_HANDLETYPE hComponent, OMX_PTR pAppData, OMX_BUFFERHEADERTYPE* pBuffer);
OMX_ERRORTYPE EmptyThisBuffer(OMX_BUFFERHEADERTYPE *omx_buffer);
OMX_ERRORTYPE FillThisBuffer(OMX_BUFFERHEADERTYPE *omx_buffer);
OMX_ERRORTYPE FreeOutputBuffer(OMX_BUFFERHEADERTYPE *omx_buffer);
unsigned int GetInputBufferSize();
unsigned int GetOutputBufferSize();
unsigned int GetInputBufferSpace();
unsigned int GetOutputBufferSpace();
void FlushAll();
void FlushInput();
void FlushOutput();
OMX_BUFFERHEADERTYPE *GetInputBuffer(long timeout=200);
OMX_BUFFERHEADERTYPE *GetOutputBuffer(long timeout=200);
OMX_ERRORTYPE AllocInputBuffers(void);
OMX_ERRORTYPE AllocOutputBuffers(void);
OMX_ERRORTYPE FreeInputBuffers(bool wait);
OMX_ERRORTYPE FreeOutputBuffers(bool wait);
bool IsEOS() { return m_eos; };
private:
OMX_HANDLETYPE m_handle;
unsigned int m_input_port;
unsigned int m_output_port;
int m_ports_enabled[OMX_MAX_PORTS];
CStdString m_componentName;
pthread_mutex_t m_omx_event_mutex;
std::vector<omx_event> m_omx_events;
OMX_CALLBACKTYPE m_callbacks;
// OMXCore input buffers (demuxer packets)
pthread_mutex_t m_omx_input_mutex;
std::queue<OMX_BUFFERHEADERTYPE*> m_omx_input_avaliable;
std::vector<OMX_BUFFERHEADERTYPE*> m_omx_input_buffers;
unsigned int m_input_alignment;
unsigned int m_input_buffer_size;
unsigned int m_input_buffer_count;
// OMXCore output buffers (video frames)
pthread_mutex_t m_omx_output_mutex;
std::queue<OMX_BUFFERHEADERTYPE*> m_omx_output_avaliable;
std::vector<OMX_BUFFERHEADERTYPE*> m_omx_output_buffers;
unsigned int m_output_alignment;
unsigned int m_output_buffer_size;
unsigned int m_output_buffer_count;
bool m_exit;
DllOMX *m_DllOMX;
bool m_DllOMXOpen;
pthread_cond_t m_input_buffer_cond;
pthread_cond_t m_output_buffer_cond;
pthread_cond_t m_omx_event_cond;
bool m_eos;
bool m_flush_input;
bool m_flush_output;
};
class COMXCore
{
public:
COMXCore();
~COMXCore();
// initialize OMXCore and get decoder component
bool Initialize();
void Deinitialize();
protected:
bool m_is_open;
bool m_Initialized;
DllOMX *m_DllOMX;
};
#endif

78
OMXOverlay.h Normal file
View file

@ -0,0 +1,78 @@
#pragma once
/*
* Copyright (C) 2006-2010 Team XBMC
* http://www.xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with XBMC; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#include <stdlib.h>
#include <assert.h>
#include <vector>
enum OMXOverlayType
{
OMXOVERLAY_TYPE_NONE = -1,
OMXOVERLAY_TYPE_SPU = 1,
OMXOVERLAY_TYPE_TEXT = 2,
OMXOVERLAY_TYPE_IMAGE = 3,
OMXOVERLAY_TYPE_SSA = 4
};
class COMXOverlay
{
public:
COMXOverlay(OMXOverlayType type)
{
m_type = type;
iPTSStartTime = 0LL;
iPTSStopTime = 0LL;
bForced = false;
replace = false;
iGroupId = 0;
}
COMXOverlay(const COMXOverlay& src)
{
m_type = src.m_type;
iPTSStartTime = src.iPTSStartTime;
iPTSStopTime = src.iPTSStopTime;
bForced = src.bForced;
replace = src.replace;
iGroupId = src.iGroupId;
}
virtual ~COMXOverlay()
{
}
bool IsOverlayType(OMXOverlayType type) { return (m_type == type); }
double iPTSStartTime;
double iPTSStopTime;
bool bForced; // display, no matter what
bool replace; // replace by next nomatter what stoptime it has
int iGroupId;
protected:
OMXOverlayType m_type;
};
typedef std::vector<COMXOverlay*> VecOMXOverlays;
typedef std::vector<COMXOverlay*>::iterator VecOMXOverlaysIter;

88
OMXOverlayCodec.h Normal file
View file

@ -0,0 +1,88 @@
#pragma once
/*
* Copyright (C) 2005-2008 Team XBMC
* http://www.xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with XBMC; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#include "OMXOverlay.h"
#include "PlatformDefs.h"
#include <string>
// VC_ messages, messages can be combined
#define OC_ERROR 0x00000001 // an error occured, no other messages will be returned
#define OC_BUFFER 0x00000002 // the decoder needs more data
#define OC_OVERLAY 0x00000004 // the decoder decoded an overlay, call Decode(NULL, 0) again to parse the rest of the data
class COMXStreamInfo;
class COMXOverlayCodec
{
public:
COMXOverlayCodec(const char* name)
{
m_codecName = name;
}
virtual ~COMXOverlayCodec() {}
/*
* Open the decoder, returns true on success
*/
virtual bool Open(COMXStreamInfo &hints) = 0;
/*
* Dispose, Free all resources
*/
virtual void Dispose() = 0;
/*
* returns one or a combination of VC_ messages
* pData and iSize can be NULL, this means we should flush the rest of the data.
*/
virtual int Decode(BYTE* data, int size, double pts, double duration) = 0;
/*
* Reset the decoder.
* Should be the same as calling Dispose and Open after each other
*/
virtual void Reset() = 0;
/*
* Flush the current working packet
* This may leave the internal state intact
*/
virtual void Flush() = 0;
/*
* returns a valid overlay or NULL
* the data is valid until the next Decode call
*/
virtual COMXOverlay* GetOverlay() = 0;
/*
* return codecs name
*/
virtual const char* GetName() { return m_codecName.c_str(); }
private:
std::string m_codecName;
};

152
OMXOverlayCodecText.cpp Normal file
View file

@ -0,0 +1,152 @@
/*
* Copyright (C) 2005-2008 Team XBMC
* http://www.xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with XBMC; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#include "system.h"
#include "OMXOverlayCodecText.h"
#include "OMXOverlayText.h"
#include "OMXStreamInfo.h"
#include "utils/log.h"
#include "OMXSubtitleTagSami.h"
COMXOverlayCodecText::COMXOverlayCodecText() : COMXOverlayCodec("Text Subtitle Decoder")
{
m_pOverlay = NULL;
m_bIsSSA = false;
}
COMXOverlayCodecText::~COMXOverlayCodecText()
{
if(m_pOverlay)
delete m_pOverlay;
m_pOverlay = NULL;
}
bool COMXOverlayCodecText::Open(COMXStreamInfo &hints)
{
m_bIsSSA = (hints.codec == CODEC_ID_SSA);
if(hints.codec == CODEC_ID_TEXT || hints.codec == CODEC_ID_SSA)
return true;
return false;
}
void COMXOverlayCodecText::Dispose()
{
if(m_pOverlay)
delete m_pOverlay;
m_pOverlay = NULL;
}
int COMXOverlayCodecText::Decode(BYTE* data, int size, double pts, double duration)
{
if(m_pOverlay)
delete m_pOverlay;
m_pOverlay = NULL;
m_pOverlay = new COMXOverlayText();
m_pOverlay->iPTSStartTime = 0;
m_pOverlay->iPTSStopTime = 0;
char *start, *end, *p;
start = (char*)data;
end = (char*)data + size;
p = (char*)data;
if (m_bIsSSA)
{
// currently just skip the prefixed ssa fields (8 fields)
int nFieldCount = 8;
while (nFieldCount > 0 && start < end)
{
if (*start == ',')
nFieldCount--;
start++;
p++;
}
}
COMXSubtitleTagSami TagConv;
bool Taginit = TagConv.Init();
while(p<end)
{
if(*p == '{')
{
if(p>start)
{
if(Taginit)
TagConv.ConvertLine(m_pOverlay, start, p-start);
else
m_pOverlay->AddElement(new COMXOverlayText::CElementText(start, p-start));
}
start = p+1;
while(*p != '}' && p<end)
p++;
char* override = (char*)malloc(p-start + 1);
memcpy(override, start, p-start);
override[p-start] = '\0';
CLog::Log(LOGINFO, "%s - Skipped formatting tag %s", __FUNCTION__, override);
free(override);
start = p+1;
}
p++;
}
if(p>start)
{
if(Taginit)
{
TagConv.ConvertLine(m_pOverlay, start, p-start);
TagConv.CloseTag(m_pOverlay);
}
else
m_pOverlay->AddElement(new COMXOverlayText::CElementText(start, p-start));
}
return OC_OVERLAY;
}
void COMXOverlayCodecText::Reset()
{
if(m_pOverlay)
delete m_pOverlay;
m_pOverlay = NULL;
}
void COMXOverlayCodecText::Flush()
{
if(m_pOverlay)
delete m_pOverlay;
m_pOverlay = NULL;
}
COMXOverlay* COMXOverlayCodecText::GetOverlay()
{
if(m_pOverlay)
{
COMXOverlay* overlay = m_pOverlay;
m_pOverlay = NULL;
return overlay;
}
return NULL;
}

43
OMXOverlayCodecText.h Normal file
View file

@ -0,0 +1,43 @@
#pragma once
/*
* Copyright (C) 2005-2008 Team XBMC
* http://www.xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with XBMC; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#include "OMXOverlayCodec.h"
class COMXOverlayText;
class COMXOverlayCodecText : public COMXOverlayCodec
{
public:
COMXOverlayCodecText();
virtual ~COMXOverlayCodecText();
virtual bool Open(COMXStreamInfo &hints);
virtual void Dispose();
virtual int Decode(BYTE* data, int size, double pts, double duration);
virtual void Reset();
virtual void Flush();
virtual COMXOverlay* GetOverlay();
private:
bool m_bIsSSA;
COMXOverlayText* m_pOverlay;
};

129
OMXOverlayText.h Normal file
View file

@ -0,0 +1,129 @@
#pragma once
/*
* Copyright (C) 2005-2008 Team XBMC
* http://www.xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with XBMC; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#include "OMXOverlay.h"
#include <string.h>
class COMXOverlayText : public COMXOverlay
{
public:
enum ElementType
{
ELEMENT_TYPE_NONE = -1,
ELEMENT_TYPE_TEXT = 1,
ELEMENT_TYPE_PROPERTY = 2
};
class CElement
{
public:
CElement(ElementType type)
{
m_type = type;
}
virtual ~CElement()
{
}
bool IsElementType(ElementType type) { return (type == m_type); }
CElement* pNext;
ElementType m_type;
};
class CElementText : public CElement
{
public:
CElementText(const char* strText, int size = -1) : CElement(ELEMENT_TYPE_TEXT)
{
if(size == -1)
m_text = strdup(strText);
else
{
m_text = (char*)malloc(size+1);
memcpy(m_text, strText, size);
m_text[size] = '\0';
}
}
virtual ~CElementText()
{
if (m_text) free(m_text);
}
char* m_text;
};
class CElementProperty : public CElement
{
CElementProperty() : CElement(ELEMENT_TYPE_PROPERTY)
{
bItalic = false;
bBold = false;
}
public:
bool bItalic;
bool bBold;
// color
};
COMXOverlayText() : COMXOverlay(OMXOVERLAY_TYPE_TEXT)
{
m_pHead = NULL;
m_pEnd = NULL;
}
virtual ~COMXOverlayText()
{
CElement* pTemp;
while (m_pHead)
{
pTemp = m_pHead;
m_pHead = m_pHead->pNext;
delete pTemp;
}
}
void AddElement(COMXOverlayText::CElement* pElement)
{
pElement->pNext = NULL;
if (!m_pHead)
{ // first element - set our head to this element, and update the end to the new element
m_pHead = pElement;
m_pEnd = pElement;
}
else
{ // extra element - add to the end and update the end to the new element
m_pEnd->pNext = pElement;
m_pEnd = pElement;
}
}
CElement* m_pHead;
CElement* m_pEnd;
};

721
OMXPlayerAudio.cpp Normal file
View file

@ -0,0 +1,721 @@
/*
* Copyright (C) 2005-2008 Team XBMC
* http://www.xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with XBMC; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#if (defined HAVE_CONFIG_H) && (!defined WIN32)
#include "config.h"
#elif defined(_WIN32)
#include "system.h"
#endif
#include "OMXPlayerAudio.h"
#include <stdio.h>
#include <unistd.h>
#ifndef STANDALONE
#include "FileItem.h"
#endif
#include "linux/XMemUtils.h"
#ifndef STANDALONE
#include "utils/BitstreamStats.h"
#include "settings/GUISettings.h"
#include "settings/Settings.h"
#endif
#define MAX_DATA_SIZE 3 * 1024 * 1024
OMXPlayerAudio::OMXPlayerAudio()
{
m_open = false;
m_stream_id = -1;
m_pStream = NULL;
m_av_clock = NULL;
m_omx_reader = NULL;
m_decoder = NULL;
m_flush = false;
m_cached_size = 0;
m_pChannelMap = NULL;
m_pAudioCodec = NULL;
m_speed = DVD_PLAYSPEED_NORMAL;
m_player_error = true;
pthread_cond_init(&m_packet_cond, NULL);
pthread_cond_init(&m_audio_cond, NULL);
pthread_mutex_init(&m_lock, NULL);
pthread_mutex_init(&m_lock_decoder, NULL);
}
OMXPlayerAudio::~OMXPlayerAudio()
{
Close();
pthread_cond_destroy(&m_audio_cond);
pthread_cond_destroy(&m_packet_cond);
pthread_mutex_destroy(&m_lock);
pthread_mutex_destroy(&m_lock_decoder);
}
void OMXPlayerAudio::Lock()
{
if(m_use_thread)
pthread_mutex_lock(&m_lock);
}
void OMXPlayerAudio::UnLock()
{
if(m_use_thread)
pthread_mutex_unlock(&m_lock);
}
void OMXPlayerAudio::LockDecoder()
{
if(m_use_thread)
pthread_mutex_lock(&m_lock_decoder);
}
void OMXPlayerAudio::UnLockDecoder()
{
if(m_use_thread)
pthread_mutex_unlock(&m_lock_decoder);
}
bool OMXPlayerAudio::Open(COMXStreamInfo &hints, OMXClock *av_clock, OMXReader *omx_reader, CStdString device,
bool passthrough, bool hw_decode, bool use_thread)
{
if(ThreadHandle())
Close();
if (!m_dllAvUtil.Load() || !m_dllAvCodec.Load() || !m_dllAvFormat.Load() || !av_clock)
return false;
m_dllAvFormat.av_register_all();
m_hints = hints;
m_av_clock = av_clock;
m_omx_reader = omx_reader;
m_device = device;
m_passthrough = IAudioRenderer::ENCODED_NONE;
m_hw_decode = false;
m_use_passthrough = passthrough;
m_use_hw_decode = hw_decode;
m_iCurrentPts = DVD_NOPTS_VALUE;
m_bAbort = false;
m_bMpeg = m_omx_reader->IsMpegVideo();
m_use_thread = use_thread;
m_flush = false;
m_cached_size = 0;
m_pAudioCodec = NULL;
m_pChannelMap = NULL;
m_speed = DVD_PLAYSPEED_NORMAL;
m_error = 0;
m_errorbuff = 0;
m_errorcount = 0;
m_integral = 0;
m_skipdupcount = 0;
m_prevskipped = false;
m_syncclock = true;
m_errortime = m_av_clock->CurrentHostCounter();
m_freq = m_av_clock->CurrentHostFrequency();
m_av_clock->SetMasterClock(false);
m_player_error = OpenAudioCodec();
if(!m_player_error)
{
Close();
return false;
}
m_player_error = OpenDecoder();
if(!m_player_error)
{
Close();
return false;
}
if(m_use_thread)
Create();
m_open = true;
return true;
}
bool OMXPlayerAudio::Close()
{
m_bAbort = true;
m_flush = true;
Flush();
if(ThreadHandle())
{
Lock();
pthread_cond_broadcast(&m_packet_cond);
UnLock();
StopThread();
}
CloseDecoder();
CloseAudioCodec();
m_open = false;
m_stream_id = -1;
m_iCurrentPts = DVD_NOPTS_VALUE;
m_pStream = NULL;
m_speed = DVD_PLAYSPEED_NORMAL;
m_dllAvUtil.Unload();
m_dllAvCodec.Unload();
m_dllAvFormat.Unload();
return true;
}
void OMXPlayerAudio::HandleSyncError(double duration, double pts)
{
double clock = m_av_clock->GetClock();
double error = pts - clock;
int64_t now;
if( fabs(error) > DVD_MSEC_TO_TIME(100) || m_syncclock )
{
m_av_clock->Discontinuity(clock+error);
/*
if(m_speed == DVD_PLAYSPEED_NORMAL)
printf("OMXPlayerAudio:: Discontinuity - was:%f, should be:%f, error:%f\n", clock, clock+error, error);
*/
m_errorbuff = 0;
m_errorcount = 0;
m_skipdupcount = 0;
m_error = 0;
m_syncclock = false;
m_errortime = m_av_clock->CurrentHostCounter();
return;
}
if (m_speed != DVD_PLAYSPEED_NORMAL)
{
m_errorbuff = 0;
m_errorcount = 0;
m_integral = 0;
m_skipdupcount = 0;
m_error = 0;
m_errortime = m_av_clock->CurrentHostCounter();
return;
}
//check if measured error for 1 second
now = m_av_clock->CurrentHostCounter();
if ((now - m_errortime) >= m_freq)
{
m_errortime = now;
m_error = m_errorbuff / m_errorcount;
m_errorbuff = 0;
m_errorcount = 0;
/*
if (m_synctype == SYNC_DISCON)
{
*/
double limit, error;
if (m_av_clock->GetRefreshRate(&limit) > 0)
{
//when the videoreferenceclock is running, the discontinuity limit is one vblank period
limit *= DVD_TIME_BASE;
//make error a multiple of limit, rounded towards zero,
//so it won't interfere with the sync methods in CXBMCRenderManager::WaitPresentTime
if (m_error > 0.0)
error = limit * floor(m_error / limit);
else
error = limit * ceil(m_error / limit);
}
else
{
limit = DVD_MSEC_TO_TIME(10);
error = m_error;
}
if (fabs(error) > limit - 0.001)
{
m_av_clock->Discontinuity(clock+error);
/*
if(m_speed == DVD_PLAYSPEED_NORMAL)
CLog::Log(LOGDEBUG, "CDVDPlayerAudio:: Discontinuity - was:%f, should be:%f, error:%f", clock, clock+error, error);
*/
}
}
/*
else if (m_synctype == SYNC_SKIPDUP && m_skipdupcount == 0 && fabs(m_error) > DVD_MSEC_TO_TIME(10))
if (m_skipdupcount == 0 && fabs(m_error) > DVD_MSEC_TO_TIME(10))
{
//check how many packets to skip/duplicate
m_skipdupcount = (int)(m_error / duration);
//if less than one frame off, see if it's more than two thirds of a frame, so we can get better in sync
if (m_skipdupcount == 0 && fabs(m_error) > duration / 3 * 2)
m_skipdupcount = (int)(m_error / (duration / 3 * 2));
if (m_skipdupcount > 0)
CLog::Log(LOGDEBUG, "OMXPlayerAudio:: Duplicating %i packet(s) of %.2f ms duration",
m_skipdupcount, duration / DVD_TIME_BASE * 1000.0);
else if (m_skipdupcount < 0)
CLog::Log(LOGDEBUG, "OMXPlayerAudio:: Skipping %i packet(s) of %.2f ms duration ",
m_skipdupcount * -1, duration / DVD_TIME_BASE * 1000.0);
}
}
*/
}
bool OMXPlayerAudio::Decode(OMXPacket *pkt)
{
if(!pkt)
return false;
/* last decoder reinit went wrong */
if(!m_decoder || !m_pAudioCodec)
return true;
if(!m_omx_reader->IsActive(OMXSTREAM_AUDIO, pkt->stream_index))
return true;
int channels = pkt->hints.channels;
/* 6 channel have to be mapped to 8 for PCM */
if(!m_passthrough && !m_hw_decode)
{
if(channels == 6)
channels = 8;
}
unsigned int old_bitrate = m_hints.bitrate;
unsigned int new_bitrate = pkt->hints.bitrate;
/* only check bitrate changes on CODEC_ID_DTS, CODEC_ID_AC3, CODEC_ID_EAC3 */
if(m_hints.codec != CODEC_ID_DTS && m_hints.codec != CODEC_ID_AC3 && m_hints.codec != CODEC_ID_EAC3)
{
new_bitrate = old_bitrate = 0;
}
/* audio codec changed. reinit device and decoder */
if(m_hints.codec != pkt->hints.codec ||
m_hints.channels != channels ||
m_hints.samplerate != pkt->hints.samplerate ||
old_bitrate != new_bitrate ||
m_hints.bitspersample != pkt->hints.bitspersample)
{
printf("C : %d %d %d %d %d\n", m_hints.codec, m_hints.channels, m_hints.samplerate, m_hints.bitrate, m_hints.bitspersample);
printf("N : %d %d %d %d %d\n", pkt->hints.codec, channels, pkt->hints.samplerate, pkt->hints.bitrate, pkt->hints.bitspersample);
m_av_clock->OMXPause();
CloseDecoder();
CloseAudioCodec();
m_hints = pkt->hints;
m_player_error = OpenAudioCodec();
if(!m_player_error)
return false;
m_player_error = OpenDecoder();
if(!m_player_error)
return false;
m_av_clock->OMXStateExecute();
m_av_clock->OMXReset();
m_av_clock->OMXResume();
}
if(!((unsigned long)m_decoder->GetSpace() > pkt->size))
OMXClock::OMXSleep(10);
if((unsigned long)m_decoder->GetSpace() > pkt->size)
{
if(pkt->dts != DVD_NOPTS_VALUE)
m_iCurrentPts = pkt->dts;
m_av_clock->SetPTS(m_iCurrentPts);
const uint8_t *data_dec = pkt->data;
int data_len = pkt->size;
if(!m_passthrough && !m_hw_decode)
{
while(data_len > 0)
{
int len = m_pAudioCodec->Decode((BYTE *)data_dec, data_len);
if( (len < 0) || (len > data_len) )
{
m_pAudioCodec->Reset();
break;
}
data_dec+= len;
data_len -= len;
uint8_t *decoded;
int decoded_size = m_pAudioCodec->GetData(&decoded);
if(decoded_size <=0)
continue;
int ret = 0;
if(m_bMpeg)
ret = m_decoder->AddPackets(decoded, decoded_size, DVD_NOPTS_VALUE, DVD_NOPTS_VALUE);
else
ret = m_decoder->AddPackets(decoded, decoded_size, m_iCurrentPts, m_iCurrentPts);
if(ret != decoded_size)
{
printf("error ret %d decoded_size %d\n", ret, decoded_size);
}
int n = (m_hints.channels * m_hints.bitspersample * m_hints.samplerate)>>3;
if (n > 0 && m_iCurrentPts != DVD_NOPTS_VALUE)
m_iCurrentPts += ((double)decoded_size * DVD_TIME_BASE) / n;
HandleSyncError((((double)decoded_size * DVD_TIME_BASE) / n), m_iCurrentPts);
}
}
else
{
if(m_bMpeg)
m_decoder->AddPackets(pkt->data, pkt->size, DVD_NOPTS_VALUE, DVD_NOPTS_VALUE);
else
m_decoder->AddPackets(pkt->data, pkt->size, m_iCurrentPts, m_iCurrentPts);
HandleSyncError(0, m_iCurrentPts);
}
m_av_clock->SetAudioClock(m_iCurrentPts);
return true;
}
else
{
return false;
}
}
void OMXPlayerAudio::Process()
{
OMXPacket *omx_pkt = NULL;
while(!m_bStop && !m_bAbort)
{
Lock();
if(m_packets.empty())
pthread_cond_wait(&m_packet_cond, &m_lock);
UnLock();
if(m_bAbort)
break;
Lock();
if(m_flush && omx_pkt)
{
OMXReader::FreePacket(omx_pkt);
omx_pkt = NULL;
m_flush = false;
}
else if(!omx_pkt && !m_packets.empty())
{
omx_pkt = m_packets.front();
m_cached_size -= omx_pkt->size;
m_packets.pop_front();
}
UnLock();
LockDecoder();
if(m_flush && omx_pkt)
{
OMXReader::FreePacket(omx_pkt);
omx_pkt = NULL;
m_flush = false;
}
else if(omx_pkt && Decode(omx_pkt))
{
OMXReader::FreePacket(omx_pkt);
omx_pkt = NULL;
}
UnLockDecoder();
}
if(omx_pkt)
OMXReader::FreePacket(omx_pkt);
}
void OMXPlayerAudio::Flush()
{
Lock();
LockDecoder();
m_flush = true;
while (!m_packets.empty())
{
OMXPacket *pkt = m_packets.front();
m_packets.pop_front();
OMXReader::FreePacket(pkt);
}
m_iCurrentPts = DVD_NOPTS_VALUE;
m_cached_size = 0;
if(m_decoder)
m_decoder->Flush();
m_syncclock = true;
UnLockDecoder();
UnLock();
}
bool OMXPlayerAudio::AddPacket(OMXPacket *pkt)
{
bool ret = false;
if(!pkt)
return ret;
if(m_bStop || m_bAbort)
return ret;
if((m_cached_size + pkt->size) < MAX_DATA_SIZE)
{
Lock();
m_cached_size += pkt->size;
m_packets.push_back(pkt);
UnLock();
ret = true;
pthread_cond_broadcast(&m_packet_cond);
}
return ret;
}
bool OMXPlayerAudio::OpenAudioCodec()
{
m_pAudioCodec = new COMXAudioCodecOMX();
if(!m_pAudioCodec->Open(m_hints))
{
delete m_pAudioCodec; m_pAudioCodec = NULL;
return false;
}
m_pChannelMap = m_pAudioCodec->GetChannelMap();
return true;
}
void OMXPlayerAudio::CloseAudioCodec()
{
if(m_pAudioCodec)
delete m_pAudioCodec;
m_pAudioCodec = NULL;
}
IAudioRenderer::EEncoded OMXPlayerAudio::IsPassthrough(COMXStreamInfo hints)
{
#ifndef STANDALONE
int m_outputmode = 0;
bool bitstream = false;
IAudioRenderer::EEncoded passthrough = IAudioRenderer::ENCODED_NONE;
m_outputmode = g_guiSettings.GetInt("audiooutput.mode");
switch(m_outputmode)
{
case 0:
passthrough = IAudioRenderer::ENCODED_NONE;
break;
case 1:
bitstream = true;
break;
case 2:
bitstream = true;
break;
}
if(bitstream)
{
if(hints.codec == CODEC_ID_AC3 && g_guiSettings.GetBool("audiooutput.ac3passthrough"))
{
passthrough = IAudioRenderer::ENCODED_IEC61937_AC3;
}
if(hints.codec == CODEC_ID_DTS && g_guiSettings.GetBool("audiooutput.dtspassthrough"))
{
passthrough = IAudioRenderer::ENCODED_IEC61937_DTS;
}
}
return passthrough;
#else
if(m_device == "omx:local")
return IAudioRenderer::ENCODED_NONE;
IAudioRenderer::EEncoded passthrough = IAudioRenderer::ENCODED_NONE;
if(hints.codec == CODEC_ID_AC3)
{
passthrough = IAudioRenderer::ENCODED_IEC61937_AC3;
}
if(hints.codec == CODEC_ID_EAC3)
{
passthrough = IAudioRenderer::ENCODED_IEC61937_EAC3;
}
if(hints.codec == CODEC_ID_DTS)
{
passthrough = IAudioRenderer::ENCODED_IEC61937_DTS;
}
return passthrough;
#endif
}
bool OMXPlayerAudio::OpenDecoder()
{
bool bAudioRenderOpen = false;
m_decoder = new COMXAudio();
m_decoder->SetClock(m_av_clock);
if(m_use_passthrough)
m_passthrough = IsPassthrough(m_hints);
if(!m_passthrough && m_use_hw_decode)
m_hw_decode = COMXAudio::HWDecode(m_hints.codec);
if(m_passthrough || m_use_hw_decode)
{
if(m_passthrough)
m_hw_decode = false;
bAudioRenderOpen = m_decoder->Initialize(NULL, m_device.substr(4), m_pChannelMap,
m_hints, m_av_clock, m_passthrough, m_hw_decode);
}
else
{
/* omx needs 6 channels packed into 8 for PCM */
if(m_hints.channels == 6)
m_hints.channels = 8;
bAudioRenderOpen = m_decoder->Initialize(NULL, m_device.substr(4), m_hints.channels, m_pChannelMap,
m_hints.samplerate, m_hints.bitspersample,
false, false, m_passthrough);
}
m_codec_name = m_omx_reader->GetCodecName(OMXSTREAM_AUDIO);
if(!bAudioRenderOpen)
{
delete m_decoder;
m_decoder = NULL;
return false;
}
else
{
if(m_passthrough)
{
printf("Audio codec %s channels %d samplerate %d bitspersample %d\n",
m_codec_name.c_str(), 2, m_hints.samplerate, m_hints.bitspersample);
}
else
{
printf("Audio codec %s channels %d samplerate %d bitspersample %d\n",
m_codec_name.c_str(), m_hints.channels, m_hints.samplerate, m_hints.bitspersample);
}
}
return true;
}
bool OMXPlayerAudio::CloseDecoder()
{
if(m_decoder)
delete m_decoder;
m_decoder = NULL;
return true;
}
double OMXPlayerAudio::GetDelay()
{
if(m_decoder)
return m_decoder->GetDelay();
else
return 0;
}
double OMXPlayerAudio::GetCacheTime()
{
if(m_decoder)
return m_decoder->GetCacheTime();
else
return 0;
}
void OMXPlayerAudio::WaitCompletion()
{
if(!m_decoder)
return;
while(true)
{
Lock();
if(m_packets.empty())
{
UnLock();
break;
}
UnLock();
OMXClock::OMXSleep(50);
}
m_decoder->WaitCompletion();
}
void OMXPlayerAudio::RegisterAudioCallback(IAudioCallback *pCallback)
{
if(m_decoder) m_decoder->RegisterAudioCallback(pCallback);
}
void OMXPlayerAudio::UnRegisterAudioCallback()
{
if(m_decoder) m_decoder->UnRegisterAudioCallback();
}
void OMXPlayerAudio::DoAudioWork()
{
if(m_decoder) m_decoder->DoAudioWork();
}
void OMXPlayerAudio::SetCurrentVolume(long nVolume)
{
if(m_decoder) m_decoder->SetCurrentVolume(nVolume);
}
void OMXPlayerAudio::SetSpeed(int speed)
{
m_speed = speed;
}

135
OMXPlayerAudio.h Normal file
View file

@ -0,0 +1,135 @@
/*
* Copyright (C) 2005-2008 Team XBMC
* http://www.xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with XBMC; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#ifndef _OMX_PLAYERAUDIO_H_
#define _OMX_PLAYERAUDIO_H_
#include "utils/StdString.h"
#include "DllAvUtil.h"
#include "DllAvFormat.h"
#include "DllAvFilter.h"
#include "DllAvCodec.h"
#include "DllAvCore.h"
#include "utils/PCMRemap.h"
#include "OMXReader.h"
#include "OMXClock.h"
#include "OMXStreamInfo.h"
#include "OMXAudio.h"
#include "OMXAudioCodecOMX.h"
#ifdef STANDALONE
#include "OMXThread.h"
#else
#include "threads/Thread.h"
#endif
#include <deque>
#include <sys/types.h>
using namespace std;
#ifdef STANDALONE
class OMXPlayerAudio : public OMXThread
#else
class OMXPlayerAudio : public CThread
#endif
{
protected:
AVStream *m_pStream;
int m_stream_id;
std::deque<OMXPacket *> m_packets;
DllAvUtil m_dllAvUtil;
DllAvCodec m_dllAvCodec;
DllAvFormat m_dllAvFormat;
bool m_open;
COMXStreamInfo m_hints;
double m_iCurrentPts;
pthread_cond_t m_packet_cond;
pthread_cond_t m_audio_cond;
pthread_mutex_t m_lock;
pthread_mutex_t m_lock_decoder;
OMXClock *m_av_clock;
OMXReader *m_omx_reader;
COMXAudio *m_decoder;
CStdString m_codec_name;
CStdString m_device;
bool m_use_passthrough;
bool m_use_hw_decode;
IAudioRenderer::EEncoded m_passthrough;
bool m_hw_decode;
bool m_bMpeg;
bool m_bAbort;
bool m_use_thread;
bool m_flush;
enum PCMChannels *m_pChannelMap;
unsigned int m_cached_size;
COMXAudioCodecOMX *m_pAudioCodec;
int m_speed;
double m_error; //last average error
int64_t m_errortime; //timestamp of last time we measured
int64_t m_freq;
void HandleSyncError(double duration, double pts);
double m_errorbuff; //place to store average errors
int m_errorcount;//number of errors stored
bool m_syncclock;
bool m_player_error;
double m_integral; //integral correction for resampler
int m_skipdupcount; //counter for skip/duplicate synctype
bool m_prevskipped;
void Lock();
void UnLock();
void LockDecoder();
void UnLockDecoder();
private:
public:
OMXPlayerAudio();
~OMXPlayerAudio();
bool Open(COMXStreamInfo &hints, OMXClock *av_clock, OMXReader *omx_reader, CStdString device,
bool passthrough, bool hw_decode, bool use_thread);
bool Close();
bool Decode(OMXPacket *pkt);
void Process();
void Flush();
bool AddPacket(OMXPacket *pkt);
bool OpenAudioCodec();
void CloseAudioCodec();
IAudioRenderer::EEncoded IsPassthrough(COMXStreamInfo hints);
bool OpenDecoder();
bool CloseDecoder();
double GetDelay();
double GetCacheTime();
double GetCurrentPTS() { return m_iCurrentPts; };
void WaitCompletion();
unsigned int GetCached() { return m_cached_size; };
void RegisterAudioCallback(IAudioCallback* pCallback);
void UnRegisterAudioCallback();
void DoAudioWork();
void SetCurrentVolume(long nVolume);
void SetSpeed(int iSpeed);
bool Error() { return !m_player_error; };
};
#endif

630
OMXPlayerVideo.cpp Normal file
View file

@ -0,0 +1,630 @@
/*
* Copyright (C) 2005-2008 Team XBMC
* http://www.xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with XBMC; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#if (defined HAVE_CONFIG_H) && (!defined WIN32)
#include "config.h"
#elif defined(_WIN32)
#include "system.h"
#endif
#include "OMXPlayerVideo.h"
#include <stdio.h>
#include <unistd.h>
#include <sys/time.h>
#ifndef STANDALONE
#include "FileItem.h"
#endif
#include "linux/XMemUtils.h"
#ifndef STANDALONE
#include "utils/BitstreamStats.h"
#endif
#define MAX_DATA_SIZE 10 * 1024 * 1024
OMXPlayerVideo::OMXPlayerVideo()
{
m_open = false;
m_stream_id = -1;
m_pStream = NULL;
m_av_clock = NULL;
m_decoder = NULL;
m_fps = 25.0f;
m_flush = false;
m_cached_size = 0;
m_hdmi_clock_sync = false;
m_iVideoDelay = 0;
m_pts = 0;
m_syncclock = true;
m_speed = DVD_PLAYSPEED_NORMAL;
m_iSubtitleDelay = 0;
m_pSubtitleCodec = NULL;
pthread_cond_init(&m_packet_cond, NULL);
pthread_cond_init(&m_picture_cond, NULL);
pthread_mutex_init(&m_lock, NULL);
pthread_mutex_init(&m_lock_decoder, NULL);
pthread_mutex_init(&m_lock_subtitle, NULL);
}
OMXPlayerVideo::~OMXPlayerVideo()
{
Close();
pthread_cond_destroy(&m_packet_cond);
pthread_cond_destroy(&m_picture_cond);
pthread_mutex_destroy(&m_lock);
pthread_mutex_destroy(&m_lock_decoder);
pthread_mutex_destroy(&m_lock_subtitle);
}
void OMXPlayerVideo::Lock()
{
if(m_use_thread)
pthread_mutex_lock(&m_lock);
}
void OMXPlayerVideo::UnLock()
{
if(m_use_thread)
pthread_mutex_unlock(&m_lock);
}
void OMXPlayerVideo::LockDecoder()
{
if(m_use_thread)
pthread_mutex_lock(&m_lock_decoder);
}
void OMXPlayerVideo::UnLockDecoder()
{
if(m_use_thread)
pthread_mutex_unlock(&m_lock_decoder);
}
void OMXPlayerVideo::LockSubtitles()
{
if(m_use_thread)
pthread_mutex_lock(&m_lock_subtitle);
}
void OMXPlayerVideo::UnLockSubtitles()
{
if(m_use_thread)
pthread_mutex_unlock(&m_lock_subtitle);
}
bool OMXPlayerVideo::Open(COMXStreamInfo &hints, OMXClock *av_clock, bool deinterlace, bool mpeg, int has_audio, bool hdmi_clock_sync, bool use_thread)
{
if (!m_dllAvUtil.Load() || !m_dllAvCodec.Load() || !m_dllAvFormat.Load() || !av_clock)
return false;
if(ThreadHandle())
Close();
m_dllAvFormat.av_register_all();
m_hints = hints;
m_av_clock = av_clock;
m_fps = 25.0f;
m_frametime = 0;
m_Deinterlace = deinterlace;
m_bMpeg = mpeg;
m_iCurrentPts = DVD_NOPTS_VALUE;
m_has_audio = has_audio;
m_bAbort = false;
m_use_thread = use_thread;
m_flush = false;
m_cached_size = 0;
m_iVideoDelay = 0;
m_hdmi_clock_sync = hdmi_clock_sync;
m_pts = 0;
m_syncclock = true;
m_speed = DVD_PLAYSPEED_NORMAL;
m_iSubtitleDelay = 0;
m_pSubtitleCodec = NULL;
m_FlipTimeStamp = m_av_clock->GetAbsoluteClock();
if(!OpenDecoder())
{
Close();
return false;
}
if(m_use_thread)
Create();
m_open = true;
return true;
}
bool OMXPlayerVideo::Close()
{
m_bAbort = true;
m_flush = true;
Flush();
if(ThreadHandle())
{
Lock();
pthread_cond_broadcast(&m_packet_cond);
UnLock();
StopThread();
}
CloseDecoder();
m_dllAvUtil.Unload();
m_dllAvCodec.Unload();
m_dllAvFormat.Unload();
m_open = false;
m_stream_id = -1;
m_iCurrentPts = DVD_NOPTS_VALUE;
m_pStream = NULL;
m_pts = 0;
m_syncclock = true;
m_speed = DVD_PLAYSPEED_NORMAL;
m_pSubtitleCodec = NULL;
return true;
}
void OMXPlayerVideo::Output(double pts)
{
if(m_syncclock)
{
double delay = m_FlipTimeStamp - m_av_clock->GetAbsoluteClock();
if( delay > m_frametime ) delay = m_frametime;
else if( delay < 0 ) delay = 0;
//printf("OMXPlayerVideo - GENERAL_RESYNC(%f, 1) delay %f\n", pts, m_FlipTimeStamp);
m_av_clock->Discontinuity(pts - delay);
m_syncclock = false;
}
double iSleepTime, iClockSleep, iFrameSleep, iPlayingClock, iCurrentClock, iFrameDuration;
iPlayingClock = m_av_clock->GetClock(iCurrentClock, false); // snapshot current clock
iClockSleep = pts - iPlayingClock; //sleep calculated by pts to clock comparison
iFrameSleep = m_FlipTimeStamp - iCurrentClock; // sleep calculated by duration of frame
iFrameDuration = m_frametime;
// correct sleep times based on speed
if(m_speed)
{
iClockSleep = iClockSleep * DVD_PLAYSPEED_NORMAL / m_speed;
iFrameSleep = iFrameSleep * DVD_PLAYSPEED_NORMAL / abs(m_speed);
iFrameDuration = iFrameDuration * DVD_PLAYSPEED_NORMAL / abs(m_speed);
}
else
{
iClockSleep = 0;
iFrameSleep = 0;
}
// dropping to a very low framerate is not correct (it should not happen at all)
iClockSleep = min(iClockSleep, DVD_MSEC_TO_TIME(500));
iFrameSleep = min(iFrameSleep, DVD_MSEC_TO_TIME(500));
bool m_stalled = false;
int m_autosync = 1;
if( m_stalled )
iSleepTime = iFrameSleep;
else
iSleepTime = iFrameSleep + (iClockSleep - iFrameSleep) / m_autosync;
// present the current pts of this frame to user, and include the actual
// presentation delay, to allow him to adjust for it
if( m_stalled )
m_iCurrentPts = DVD_NOPTS_VALUE;
else
m_iCurrentPts = pts - max(0.0, iSleepTime);
// timestamp when we think next picture should be displayed based on current duration
m_FlipTimeStamp = iCurrentClock;
m_FlipTimeStamp += max(0.0, iSleepTime);
m_FlipTimeStamp += iFrameDuration;
while(m_av_clock->GetAbsoluteClock(false) < (iCurrentClock + iSleepTime + DVD_MSEC_TO_TIME(500)) )
{
OMXClock::OMXSleep(10);
}
/*
printf("iPlayingClock %f iCurrentClock %f iClockSleep %f iFrameSleep %f iFrameDuration %f WaitAbsolut %f m_FlipTimeStamp %f pts %f\n",
iPlayingClock / DVD_TIME_BASE, iCurrentClock / DVD_TIME_BASE,
iClockSleep / DVD_TIME_BASE, iFrameSleep / DVD_TIME_BASE,
iFrameDuration / DVD_TIME_BASE, (iCurrentClock + iSleepTime) / DVD_TIME_BASE, m_FlipTimeStamp / DVD_TIME_BASE,
pts / DVD_TIME_BASE);
*/
//g_renderManager.FlipPage(CThread::m_bStop, (iCurrentClock + iSleepTime) / DVD_TIME_BASE, -1, mDisplayField);
m_av_clock->WaitAbsoluteClock((iCurrentClock + iSleepTime));
// guess next frame pts. iDuration is always valid
if (m_speed != 0)
m_pts += m_frametime * m_speed / abs(m_speed);
}
bool OMXPlayerVideo::Decode(OMXPacket *pkt)
{
if(!pkt)
return false;
bool ret = false;
if(!((unsigned long)m_decoder->GetFreeSpace() > pkt->size))
OMXClock::OMXSleep(10);
if (pkt->dts == DVD_NOPTS_VALUE && pkt->pts == DVD_NOPTS_VALUE)
pkt->pts = m_pts;
else if (pkt->pts == DVD_NOPTS_VALUE)
pkt->pts = pkt->dts;
if(pkt->pts != DVD_NOPTS_VALUE)
{
m_pts = pkt->pts;
m_pts += m_iVideoDelay;
}
if(pkt->hints.codec == CODEC_ID_TEXT ||
pkt->hints.codec == CODEC_ID_SSA )
{
if(!m_pSubtitleCodec)
{
m_pSubtitleCodec = new COMXOverlayCodecText();
m_pSubtitleCodec->Open( pkt->hints );
}
int result = m_pSubtitleCodec->Decode(pkt->data, pkt->size, pkt->pts, pkt->duration);
COMXOverlay* overlay;
CStdString strSubtitle = "";
double pts = pkt->dts != DVD_NOPTS_VALUE ? pkt->dts : pkt->pts;
double duration = pkt->duration;
if(result == OC_OVERLAY)
{
while((overlay = m_pSubtitleCodec->GetOverlay()) != NULL)
{
if(overlay->iPTSStopTime > overlay->iPTSStartTime)
duration = overlay->iPTSStopTime - overlay->iPTSStartTime;
else if(pkt->duration != DVD_NOPTS_VALUE)
duration = pkt->duration;
else
duration = 0.0;
if (pkt->pts != DVD_NOPTS_VALUE)
pts = pkt->pts;
else if(pkt->dts != DVD_NOPTS_VALUE)
pts = pkt->dts;
else
pts = overlay->iPTSStartTime;
pts -= m_iSubtitleDelay;
overlay->iPTSStartTime = pts;
if(duration)
overlay->iPTSStopTime = pts + duration;
else
{
overlay->iPTSStopTime = 0;
overlay->replace = true;
}
COMXOverlayText::CElement* e = ((COMXOverlayText*)overlay)->m_pHead;
while (e)
{
if (e->IsElementType(COMXOverlayText::ELEMENT_TYPE_TEXT))
{
COMXOverlayText::CElementText* t = (COMXOverlayText::CElementText*)e;
strSubtitle += t->m_text;
strSubtitle += "\n";
}
e = e->pNext;
}
m_overlays.push_back(overlay);
if(strSubtitle.length())
m_decoder->DecodeText((uint8_t *)strSubtitle.c_str(), strSubtitle.length(), overlay->iPTSStartTime, overlay->iPTSStartTime);
}
}
ret = true;
}
else if((unsigned long)m_decoder->GetFreeSpace() > pkt->size)
{
if(m_bMpeg)
m_decoder->Decode(pkt->data, pkt->size, DVD_NOPTS_VALUE, DVD_NOPTS_VALUE);
else
m_decoder->Decode(pkt->data, pkt->size, m_pts, m_pts);
m_av_clock->SetVideoClock(m_pts);
Output(m_pts);
ret = true;
}
return ret;
}
void OMXPlayerVideo::Process()
{
OMXPacket *omx_pkt = NULL;
m_pts = 0;
while(!m_bStop && !m_bAbort)
{
Lock();
if(m_packets.empty())
pthread_cond_wait(&m_packet_cond, &m_lock);
UnLock();
if(m_bAbort)
break;
Lock();
if(m_flush && omx_pkt)
{
OMXReader::FreePacket(omx_pkt);
omx_pkt = NULL;
m_flush = false;
}
else if(!omx_pkt && !m_packets.empty())
{
omx_pkt = m_packets.front();
m_cached_size -= omx_pkt->size;
m_packets.pop_front();
}
UnLock();
LockDecoder();
if(m_flush && omx_pkt)
{
OMXReader::FreePacket(omx_pkt);
omx_pkt = NULL;
m_flush = false;
}
else if(omx_pkt && Decode(omx_pkt))
{
OMXReader::FreePacket(omx_pkt);
omx_pkt = NULL;
}
UnLockDecoder();
OMXPacket *subtitle_pkt = m_decoder->GetText();
if(subtitle_pkt)
{
LockSubtitles();
subtitle_pkt->pts = m_av_clock->GetClock();
m_subtitle_packets.push_back(subtitle_pkt);
UnLockSubtitles();
}
}
if(omx_pkt)
OMXReader::FreePacket(omx_pkt);
}
void OMXPlayerVideo::FlushSubtitles()
{
LockDecoder();
LockSubtitles();
while (!m_subtitle_packets.empty())
{
OMXPacket *pkt = m_subtitle_packets.front();
m_subtitle_packets.pop_front();
OMXReader::FreePacket(pkt);
}
while (!m_overlays.empty())
{
COMXOverlay *overlay = m_overlays.front();
m_overlays.pop_front();
delete overlay;
}
if(m_pSubtitleCodec)
delete m_pSubtitleCodec;
m_pSubtitleCodec = NULL;
UnLockSubtitles();
UnLockDecoder();
}
void OMXPlayerVideo::Flush()
{
Lock();
LockDecoder();
m_flush = true;
while (!m_packets.empty())
{
OMXPacket *pkt = m_packets.front();
m_packets.pop_front();
OMXReader::FreePacket(pkt);
}
m_iCurrentPts = DVD_NOPTS_VALUE;
m_cached_size = 0;
if(m_decoder)
m_decoder->Reset();
m_syncclock = true;
UnLockDecoder();
FlushSubtitles();
UnLock();
}
bool OMXPlayerVideo::AddPacket(OMXPacket *pkt)
{
bool ret = false;
if(!pkt)
return ret;
if(m_bStop || m_bAbort)
return ret;
if((m_cached_size + pkt->size) < MAX_DATA_SIZE)
{
Lock();
m_cached_size += pkt->size;
m_packets.push_back(pkt);
UnLock();
ret = true;
pthread_cond_broadcast(&m_packet_cond);
}
return ret;
}
bool OMXPlayerVideo::OpenDecoder()
{
if (m_hints.fpsrate && m_hints.fpsscale)
m_fps = DVD_TIME_BASE / OMXReader::NormalizeFrameduration((double)DVD_TIME_BASE * m_hints.fpsscale / m_hints.fpsrate);
else
m_fps = 25;
if( m_fps > 100 || m_fps < 5 )
{
printf("Invalid framerate %d, using forced 25fps and just trust timestamps\n", (int)m_fps);
m_fps = 25;
}
m_frametime = (double)DVD_TIME_BASE / m_fps;
m_decoder = new COMXVideo();
if(!m_decoder->Open(m_hints, m_av_clock, m_Deinterlace, m_hdmi_clock_sync))
{
CloseDecoder();
return false;
}
else
{
printf("Video codec %s width %d height %d profile %d fps %f\n",
m_decoder->GetDecoderName().c_str() , m_hints.width, m_hints.height, m_hints.profile, m_fps);
}
if(m_av_clock)
m_av_clock->SetRefreshRate(m_fps);
return true;
}
bool OMXPlayerVideo::CloseDecoder()
{
if(m_decoder)
delete m_decoder;
m_decoder = NULL;
return true;
}
int OMXPlayerVideo::GetDecoderBufferSize()
{
if(m_decoder)
return m_decoder->GetInputBufferSize();
else
return 0;
}
int OMXPlayerVideo::GetDecoderFreeSpace()
{
if(m_decoder)
return m_decoder->GetFreeSpace();
else
return 0;
}
void OMXPlayerVideo::WaitCompletion()
{
if(!m_decoder)
return;
while(true)
{
Lock();
if(m_packets.empty())
{
UnLock();
break;
}
UnLock();
OMXClock::OMXSleep(50);
}
m_decoder->WaitCompletion();
}
void OMXPlayerVideo::SetSpeed(int speed)
{
m_speed = speed;
}
CStdString OMXPlayerVideo::GetText()
{
OMXPacket *pkt = NULL;
CStdString strSubtitle = "";
LockSubtitles();
if (!m_subtitle_packets.empty())
{
pkt = m_subtitle_packets.front();
if(!m_overlays.empty())
{
COMXOverlay *overlay = m_overlays.front();
double now = m_av_clock->GetClock();
double iPTSStartTime = pkt->pts;
double iPTSStopTime = (overlay->iPTSStartTime > 0) ? iPTSStartTime + (overlay->iPTSStopTime - overlay->iPTSStartTime) : 0LL;
if((iPTSStartTime <= now)
&& (iPTSStopTime >= now || iPTSStopTime == 0LL))
{
COMXOverlayText::CElement* e = ((COMXOverlayText*)overlay)->m_pHead;
while (e)
{
if (e->IsElementType(COMXOverlayText::ELEMENT_TYPE_TEXT))
{
COMXOverlayText::CElementText* t = (COMXOverlayText::CElementText*)e;
strSubtitle += t->m_text;
strSubtitle += "\n";
}
e = e->pNext;
}
}
else if(iPTSStopTime < now)
{
m_subtitle_packets.pop_front();
m_overlays.pop_front();
delete overlay;
OMXReader::FreePacket(pkt);
}
}
}
UnLockSubtitles();
return strSubtitle;
}

128
OMXPlayerVideo.h Normal file
View file

@ -0,0 +1,128 @@
/*
* Copyright (C) 2005-2008 Team XBMC
* http://www.xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with XBMC; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#ifndef _OMX_PLAYERVIDEO_H_
#define _OMX_PLAYERVIDEO_H_
#include "utils/StdString.h"
#include "DllAvUtil.h"
#include "DllAvFormat.h"
#include "DllAvFilter.h"
#include "DllAvCodec.h"
#include "DllAvCore.h"
#include "OMXReader.h"
#include "OMXClock.h"
#include "OMXStreamInfo.h"
#include "OMXVideo.h"
#ifdef STANDALONE
#include "OMXThread.h"
#else
#include "threads/Thread.h"
#endif
#include <deque>
#include <sys/types.h>
#include "OMXOverlayCodec.h"
#include "OMXOverlayText.h"
#include "OMXOverlayCodecText.h"
using namespace std;
#ifdef STANDALONE
class OMXPlayerVideo : public OMXThread
#else
class OMXPlayerVideo : public CThread
#endif
{
protected:
AVStream *m_pStream;
int m_stream_id;
std::deque<OMXPacket *> m_subtitle_packets;
std::deque<OMXPacket *> m_packets;
std::deque<COMXOverlay *> m_overlays;
DllAvUtil m_dllAvUtil;
DllAvCodec m_dllAvCodec;
DllAvFormat m_dllAvFormat;
bool m_open;
COMXStreamInfo m_hints;
double m_iCurrentPts;
pthread_cond_t m_packet_cond;
pthread_cond_t m_picture_cond;
pthread_mutex_t m_lock;
pthread_mutex_t m_subtitle;
pthread_mutex_t m_lock_decoder;
pthread_mutex_t m_lock_subtitle;
OMXClock *m_av_clock;
COMXVideo *m_decoder;
float m_fps;
double m_frametime;
bool m_Deinterlace;
bool m_bMpeg;
int m_has_audio;
bool m_bAbort;
bool m_use_thread;
bool m_flush;
unsigned int m_cached_size;
bool m_hdmi_clock_sync;
double m_iVideoDelay;
double m_pts;
bool m_syncclock;
int m_speed;
double m_FlipTimeStamp; // time stamp of last flippage. used to play at a forced framerate
double m_iSubtitleDelay;
COMXOverlayCodec *m_pSubtitleCodec;
void Lock();
void UnLock();
void LockDecoder();
void UnLockDecoder();
void LockSubtitles();
void UnLockSubtitles();
private:
public:
OMXPlayerVideo();
~OMXPlayerVideo();
bool Open(COMXStreamInfo &hints, OMXClock *av_clock, bool deinterlace, bool mpeg, int has_audio, bool hdmi_clock_sync, bool use_thread);
bool Close();
void Output(double pts);
bool Decode(OMXPacket *pkt);
void Process();
void FlushSubtitles();
void Flush();
bool AddPacket(OMXPacket *pkt);
bool OpenDecoder();
bool CloseDecoder();
int GetDecoderBufferSize();
int GetDecoderFreeSpace();
double GetCurrentPTS() { return m_pts; };
double GetFPS() { return m_fps; };
unsigned int GetCached() { return m_cached_size; };
void WaitCompletion();
void SetDelay(double delay) { m_iVideoDelay = delay; }
double GetDelay() { return m_iVideoDelay; }
void SetSpeed(int iSpeed);
double GetSubtitleDelay() { return m_iSubtitleDelay; }
void SetSubtitleDelay(double delay) { m_iSubtitleDelay = delay; }
CStdString GetText();
};
#endif

1429
OMXReader.cpp Normal file

File diff suppressed because it is too large Load diff

202
OMXReader.h Normal file
View file

@ -0,0 +1,202 @@
/*
* Copyright (C) 2005-2008 Team XBMC
* http://www.xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with XBMC; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#ifndef _OMX_READER_H_
#define _OMX_READER_H_
#include "utils/StdString.h"
#include "DllAvUtil.h"
#include "DllAvFormat.h"
#include "DllAvFilter.h"
#include "DllAvCodec.h"
#include "DllAvCore.h"
#include "OMXStreamInfo.h"
#ifdef STANDALONE
#include "OMXThread.h"
#else
#include "threads/Thread.h"
#endif
#include <queue>
#include "OMXStreamInfo.h"
#ifdef STANDALONE
#include "File.h"
#else
#include "xbmc/filesystem/File.h"
#endif
#include <sys/types.h>
using namespace XFILE;
using namespace std;
#define MAX_OMX_CHAPTERS 64
#define MAX_OMX_STREAMS 100
#define OMX_PLAYSPEED_PAUSE 0
#define OMX_PLAYSPEED_NORMAL 1
#ifndef FFMPEG_FILE_BUFFER_SIZE
#define FFMPEG_FILE_BUFFER_SIZE 32768 // default reading size for ffmpeg
#endif
#ifndef MAX_STREAMS
#define MAX_STREAMS 100
#endif
typedef struct OMXChapter
{
std::string name;
int64_t seekto_ms;
double ts;
} OMXChapter;
class OMXReader;
typedef struct OMXPacket
{
double pts; // pts in DVD_TIME_BASE
double dts; // dts in DVD_TIME_BASE
double now; // dts in DVD_TIME_BASE
double duration; // duration in DVD_TIME_BASE if available
int size;
uint8_t *data;
int stream_index;
COMXStreamInfo hints;
enum AVMediaType codec_type;
} OMXPacket;
enum OMXStreamType
{
OMXSTREAM_NONE = 0,
OMXSTREAM_AUDIO = 1,
OMXSTREAM_VIDEO = 2,
OMXSTREAM_SUBTITLE = 3
};
typedef struct OMXStream
{
char language[4];
std::string name;
std::string codec_name;
AVStream *stream;
OMXStreamType type;
int id;
void *extradata;
unsigned int extrasize;
unsigned int index;
COMXStreamInfo hints;
} OMXStream;
class OMXReader
{
protected:
int m_video_index;
int m_audio_index;
int m_subtitle_index;
int m_video_count;
int m_audio_count;
int m_subtitle_count;
DllAvUtil m_dllAvUtil;
DllAvCodec m_dllAvCodec;
DllAvFormat m_dllAvFormat;
bool m_open;
CStdString m_filename;
bool m_bMatroska;
bool m_bAVI;
bool m_bMpeg;
XFILE::CFile *m_pFile;
AVFormatContext *m_pFormatContext;
ByteIOContext *m_ioContext;
bool m_eof;
OMXChapter m_chapters[MAX_OMX_CHAPTERS];
OMXStream m_streams[MAX_STREAMS];
int m_chapter_count;
double m_iCurrentPts;
int64_t m_seek_ms;
int m_seek_req;
int m_seek_flags;
int m_speed;
int64_t m_duration_ms;
unsigned int m_program;
void AddTimespecs(struct timespec &time, long millisecs);
#ifdef STANDALONE
void flush_packet_queue(AVFormatContext *s);
void av_read_frame_flush(AVFormatContext *s);
#endif
pthread_mutex_t m_lock;
void Lock();
void UnLock();
bool SetActiveStreamInternal(OMXStreamType type, unsigned int index);
private:
public:
OMXReader();
~OMXReader();
bool Open(CStdString filename, bool dump_format);
void ClearStreams();
bool Close();
void FlushRead();
bool SeekTime(int64_t seek_ms, int seek_flags, double *startpts);
AVMediaType PacketType(OMXPacket *pkt);
OMXPacket *Read();
void Process();
bool GetStreams();
void AddStream(int id);
bool IsActive(int stream_index);
bool IsActive(OMXStreamType type, int stream_index);
bool GetHints(AVStream *stream, COMXStreamInfo *hints);
bool GetHints(OMXStreamType type, unsigned int index, COMXStreamInfo &hints);
bool GetHints(OMXStreamType type, COMXStreamInfo &hints);
bool IsEof();
int AudioStreamCount() { return m_audio_count; };
int VideoStreamCount() { return m_video_count; };
int SubtitleStreamCount() { return m_subtitle_count; };
bool SetActiveStream(OMXStreamType type, unsigned int index);
int GetChapterCount() { return m_chapter_count; };
OMXChapter GetChapter(unsigned int chapter) { return m_chapters[(chapter > MAX_OMX_CHAPTERS) ? MAX_OMX_CHAPTERS : chapter]; };
static void FreePacket(OMXPacket *pkt);
static OMXPacket *AllocPacket(int size);
void SetSpeed(int iSpeed);
void UpdateCurrentPTS();
double ConvertTimestamp(int64_t pts, int den, int num);
double ConvertTimestamp(int64_t pts, AVRational *time_base);
int GetChapter();
void GetChapterName(std::string& strChapterName);
bool SeekChapter(int chapter, double* startpts);
bool GetAudioIndex() { return m_audio_index; };
bool GetSubtitleIndex() { return m_subtitle_index; };
int GetStreamLength();
static double NormalizeFrameduration(double frameduration);
bool IsMpegVideo() { return m_bMpeg; };
bool IsMatroska() { return m_bMatroska; };
CStdString GetCodecName(OMXStreamType type);
CStdString GetCodecName(OMXStreamType type, unsigned int index);
CStdString GetStreamCodecName(AVStream *stream);
CStdString GetStreamLanguage(OMXStreamType type, unsigned int index);
CStdString GetStreamName(OMXStreamType type, unsigned int index);
int64_t GetDuration() { return m_duration_ms; };
CStdString GetStreamType(OMXStreamType type, unsigned int index);
#ifndef STANDALONE
int GetSourceBitrate();
#endif
};
#endif

71
OMXStreamInfo.cpp Normal file
View file

@ -0,0 +1,71 @@
/*
* Copyright (C) 2005-2008 Team XBMC
* http://www.xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with XBMC; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#include "OMXStreamInfo.h"
COMXStreamInfo::COMXStreamInfo()
{
extradata = NULL;
Clear();
}
COMXStreamInfo::~COMXStreamInfo()
{
//if( extradata && extrasize ) free(extradata);
extradata = NULL;
extrasize = 0;
}
void COMXStreamInfo::Clear()
{
codec = CODEC_ID_NONE;
software = false;
codec_tag = 0;
//if( extradata && extrasize ) free(extradata);
extradata = NULL;
extrasize = 0;
fpsscale = 0;
fpsrate = 0;
height = 0;
width = 0;
aspect = 0.0;
vfr = false;
stills = false;
level = 0;
profile = 0;
ptsinvalid = false;
channels = 0;
samplerate = 0;
blockalign = 0;
bitrate = 0;
bitspersample = 0;
identifier = 0;
framesize = 0;
syncword = 0;
}

80
OMXStreamInfo.h Normal file
View file

@ -0,0 +1,80 @@
/*
* Copyright (C) 2005-2008 Team XBMC
* http://www.xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with XBMC; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#pragma once
#if (defined HAVE_CONFIG_H) && (!defined WIN32)
#include "config.h"
#endif
#ifndef _LINUX
enum CodecID;
#else
extern "C" {
#include "libavcodec/avcodec.h"
}
#endif
class CDemuxStream;
class COMXStreamInfo
{
public:
COMXStreamInfo();
~COMXStreamInfo();
void Clear(); // clears current information
CodecID codec;
bool software; //force software decoding
// VIDEO
int fpsscale; // scale of 1000 and a rate of 29970 will result in 29.97 fps
int fpsrate;
int height; // height of the stream reported by the demuxer
int width; // width of the stream reported by the demuxer
float aspect; // display aspect as reported by demuxer
bool vfr; // variable framerate
bool stills; // there may be odd still frames in video
int level; // encoder level of the stream reported by the decoder. used to qualify hw decoders.
int profile; // encoder profile of the stream reported by the decoder. used to qualify hw decoders.
bool ptsinvalid; // pts cannot be trusted (avi's).
// AUDIO
int channels;
int samplerate;
int bitrate;
int blockalign;
int bitspersample;
// SUBTITLE
int identifier;
// CODEC EXTRADATA
void* extradata; // extra data for codec to use
unsigned int extrasize; // size of extra data
unsigned int codec_tag; // extra identifier hints for decoding
/* ac3/dts indof */
unsigned int framesize;
uint32_t syncword;
};

261
OMXSubtitleTagSami.cpp Normal file
View file

@ -0,0 +1,261 @@
/*
* Copyright (C) 2005-2008 Team XBMC
* http://www.xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with XBMC; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#include "OMXSubtitleTagSami.h"
//#include "DVDSubtitleStream.h"
#include "linux/PlatformDefs.h"
#include "OMXOverlayText.h"
#include "utils/RegExp.h"
COMXSubtitleTagSami::~COMXSubtitleTagSami()
{
delete m_tags;
delete m_tagOptions;
}
bool COMXSubtitleTagSami::Init()
{
m_tags = new CRegExp(true);
if (!m_tags->RegComp("(<[^>]*>|\\{[^\\}]*\\})"))
return false;
m_tagOptions = new CRegExp(true);
if (!m_tagOptions->RegComp("([a-z]+)[ \t]*=[ \t]*(?:[\"'])?([^\"'> ]+)(?:[\"'])?(?:>)?"))
return false;
return true;
}
void COMXSubtitleTagSami::ConvertLine(COMXOverlayText* pOverlay, const char* line, int len, const char* lang)
{
CStdStringA strUTF8;
strUTF8.assign(line, len);
strUTF8.Trim();
int pos = 0;
int del_start = 0;
while ((pos=m_tags->RegFind(strUTF8.c_str(), pos)) >= 0)
{
// Parse Tags
CStdString fullTag = m_tags->GetMatch(0);
fullTag.ToLower();
strUTF8.erase(pos, fullTag.length());
if (fullTag == "<b>" || fullTag == "{\\b1}")
{
m_flag[FLAG_BOLD] = true;
strUTF8.insert(pos, "[B]");
pos += 3;
}
else if ((fullTag == "</b>" || fullTag == "{\\b0}") && m_flag[FLAG_BOLD])
{
m_flag[FLAG_BOLD] = false;
strUTF8.insert(pos, "[/B]");
pos += 4;
}
else if (fullTag == "<i>" || fullTag == "{\\i1}")
{
m_flag[FLAG_ITALIC] = true;
strUTF8.insert(pos, "[I]");
pos += 3;
}
else if ((fullTag == "</i>" || fullTag == "{\\i0}") && m_flag[FLAG_ITALIC])
{
m_flag[FLAG_ITALIC] = false;
strUTF8.insert(pos, "[/I]");
pos += 4;
}
else if ((fullTag == "</font>" || fullTag == "{\\c}") && m_flag[FLAG_COLOR])
{
m_flag[FLAG_COLOR] = false;
strUTF8.insert(pos, "[/COLOR]");
pos += 8;
}
else if (fullTag.Left(5) == "{\\c&h" || fullTag.Left(6) == "{\\1c&h")
{
m_flag[FLAG_COLOR] = true;
CStdString tempColorTag = "[COLOR FF";
CStdString tagOptionValue;
if (fullTag.Left(5) == "{\\c&h")
tagOptionValue = fullTag.substr(5,6);
else
tagOptionValue = fullTag.substr(6,6);
tempColorTag += tagOptionValue.substr(4,2);
tempColorTag += tagOptionValue.substr(2,2);
tempColorTag += tagOptionValue.substr(0,2);
tempColorTag += "]";
strUTF8.insert(pos, tempColorTag);
pos += tempColorTag.length();
}
else if (fullTag.Left(5) == "<font")
{
int pos2 = 5;
while ((pos2 = m_tagOptions->RegFind(fullTag.c_str(), pos2)) >= 0)
{
CStdString tagOptionName = m_tagOptions->GetMatch(1);
CStdString tagOptionValue = m_tagOptions->GetMatch(2);
pos2 += tagOptionName.length() + tagOptionValue.length();
if (tagOptionName == "color")
{
m_flag[FLAG_COLOR] = true;
CStdString tempColorTag = "[COLOR ";
if (tagOptionValue[0] == '#')
{
tagOptionValue.erase(0, 1);
tempColorTag += "FF";
}
else if( tagOptionValue.size() == 6 )
{
bool bHex = true;
for( int i=0 ; i<6 ; i++ )
{
char temp = tagOptionValue[i];
if( !(('0' <= temp && temp <= '9') ||
('a' <= temp && temp <= 'f') ||
('A' <= temp && temp <= 'F') ))
{
bHex = false;
break;
}
}
if( bHex ) tempColorTag += "FF";
}
tempColorTag += tagOptionValue;
tempColorTag += "]";
strUTF8.insert(pos, tempColorTag);
pos += tempColorTag.length();
}
}
}
else if (lang && (fullTag.Left(3) == "<p "))
{
int pos2 = 3;
while ((pos2 = m_tagOptions->RegFind(fullTag.c_str(), pos2)) >= 0)
{
CStdString tagOptionName = m_tagOptions->GetMatch(1);
CStdString tagOptionValue = m_tagOptions->GetMatch(2);
pos2 += tagOptionName.length() + tagOptionValue.length();
if (tagOptionName == "class")
{
if (m_flag[FLAG_LANGUAGE])
{
strUTF8.erase(del_start, pos - del_start);
pos = del_start;
}
if (!tagOptionValue.Compare(lang))
{
m_flag[FLAG_LANGUAGE] = false;
}
else
{
m_flag[FLAG_LANGUAGE] = true;
del_start = pos;
}
break;
}
}
}
else if (fullTag == "</p>" && m_flag[FLAG_LANGUAGE])
{
strUTF8.erase(del_start, pos - del_start);
pos = del_start;
m_flag[FLAG_LANGUAGE] = false;
}
else if (fullTag == "<br>" && !strUTF8.IsEmpty())
{
strUTF8.Insert(pos, "\n");
pos += 1;
}
}
if(m_flag[FLAG_LANGUAGE])
strUTF8.erase(del_start);
if (strUTF8.IsEmpty())
return;
if( strUTF8[strUTF8.size()-1] == '\n' )
strUTF8.Delete(strUTF8.size()-1);
// add a new text element to our container
pOverlay->AddElement(new COMXOverlayText::CElementText(strUTF8.c_str()));
}
void COMXSubtitleTagSami::CloseTag(COMXOverlayText* pOverlay)
{
if (m_flag[FLAG_BOLD])
{
pOverlay->AddElement(new COMXOverlayText::CElementText("[/B]"));
m_flag[FLAG_BOLD] = false;
}
if (m_flag[FLAG_ITALIC])
{
pOverlay->AddElement(new COMXOverlayText::CElementText("[/I]"));
m_flag[FLAG_ITALIC] = false;
}
if (m_flag[FLAG_COLOR])
{
pOverlay->AddElement(new COMXOverlayText::CElementText("[/COLOR]"));
m_flag[FLAG_COLOR] = false;
}
m_flag[FLAG_LANGUAGE] = false;
}
/*
void COMXSubtitleTagSami::LoadHead(CDVDSubtitleStream* samiStream)
{
char line[1024];
bool inSTYLE = false;
CRegExp reg(true);
if (!reg.RegComp("\\.([a-z]+)[ \t]*\\{[ \t]*name:([^;]*?);[ \t]*lang:([^;]*?);[ \t]*SAMIType:([^;]*?);[ \t]*\\}"))
return;
while (samiStream->ReadLine(line, sizeof(line)))
{
if (!strnicmp(line, "<BODY>", 6))
break;
if (inSTYLE)
{
if (!strnicmp(line, "</STYLE>", 8))
break;
else
{
if (reg.RegFind(line) > -1)
{
SLangclass lc;
lc.ID = reg.GetMatch(1);
lc.Name = reg.GetMatch(2);
lc.Lang = reg.GetMatch(3);
lc.SAMIType = reg.GetMatch(4);
lc.Name.Trim();
lc.Lang.Trim();
lc.SAMIType.Trim();
m_Langclass.push_back(lc);
}
}
}
else
{
if (!strnicmp(line, "<STYLE TYPE=\"text/css\">", 23))
inSTYLE = true;
}
}
}
*/

68
OMXSubtitleTagSami.h Normal file
View file

@ -0,0 +1,68 @@
#pragma once
/*
* Copyright (C) 2005-2008 Team XBMC
* http://www.xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with XBMC; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#include <stdio.h>
#include "utils/StdString.h"
#define FLAG_BOLD 0
#define FLAG_ITALIC 1
#define FLAG_COLOR 2
#define FLAG_LANGUAGE 3
class COMXOverlayText;
class CDVDSubtitleStream;
class CRegExp;
class COMXSubtitleTagSami
{
public:
COMXSubtitleTagSami()
{
m_tags = NULL;
m_tagOptions = NULL;
m_flag[FLAG_BOLD] = false;
m_flag[FLAG_ITALIC] = false;
m_flag[FLAG_COLOR] = false;
m_flag[FLAG_LANGUAGE] = false; //set to true when classID != lang
}
virtual ~COMXSubtitleTagSami();
bool Init();
void ConvertLine(COMXOverlayText* pOverlay, const char* line, int len, const char* lang = NULL);
void CloseTag(COMXOverlayText* pOverlay);
//void LoadHead(CDVDSubtitleStream* samiStream);
typedef struct
{
CStdString ID;
CStdString Name;
CStdString Lang;
CStdString SAMIType;
} SLangclass;
std::vector<SLangclass> m_Langclass;
private:
CRegExp *m_tags;
CRegExp *m_tagOptions;
bool m_flag[4];
};

132
OMXThread.cpp Normal file
View file

@ -0,0 +1,132 @@
/*
* Copyright (C) 2005-2008 Team XBMC
* http://www.xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with XBMC; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#if (defined HAVE_CONFIG_H) && (!defined WIN32)
#include "config.h"
#elif defined(_WIN32)
#include "system.h"
#endif
#include "OMXThread.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "utils/log.h"
#ifdef CLASSNAME
#undef CLASSNAME
#endif
#define CLASSNAME "OMXThread"
OMXThread::OMXThread()
{
pthread_mutex_init(&m_lock, NULL);
pthread_attr_setdetachstate(&m_tattr, PTHREAD_CREATE_JOINABLE);
pthread_attr_init(&m_tattr);
m_thread = 0;
m_bStop = false;
m_running = false;
}
OMXThread::~OMXThread()
{
pthread_mutex_destroy(&m_lock);
pthread_attr_destroy(&m_tattr);
}
bool OMXThread::StopThread()
{
if(!m_running)
{
CLog::Log(LOGDEBUG, "%s::%s - No thread running\n", CLASSNAME, __func__);
return false;
}
m_bStop = true;
pthread_join(m_thread, NULL);
m_running = false;
m_thread = 0;
CLog::Log(LOGDEBUG, "%s::%s - Thread stopped\n", CLASSNAME, __func__);
return true;
}
bool OMXThread::Create()
{
if(m_running)
{
CLog::Log(LOGERROR, "%s::%s - Thread already running\n", CLASSNAME, __func__);
return false;
}
m_bStop = false;
m_running = true;
pthread_create(&m_thread, &m_tattr, &OMXThread::Run, this);
CLog::Log(LOGDEBUG, "%s::%s - Thread with id %d started\n", CLASSNAME, __func__, (int)m_thread);
return true;
}
bool OMXThread::Running()
{
return m_running;
}
pthread_t OMXThread::ThreadHandle()
{
return m_thread;
}
void *OMXThread::Run(void *arg)
{
OMXThread *thread = static_cast<OMXThread *>(arg);
thread->Process();
CLog::Log(LOGDEBUG, "%s::%s - Exited thread with id %d\n", CLASSNAME, __func__, (int)thread->ThreadHandle());
pthread_exit(NULL);
}
void OMXThread::Lock()
{
if(!m_running)
{
CLog::Log(LOGDEBUG, "%s::%s - No thread running\n", CLASSNAME, __func__);
return;
}
pthread_mutex_lock(&m_lock);
}
void OMXThread::UnLock()
{
if(!m_running)
{
CLog::Log(LOGDEBUG, "%s::%s - No thread running\n", CLASSNAME, __func__);
return;
}
pthread_mutex_unlock(&m_lock);
}

49
OMXThread.h Normal file
View file

@ -0,0 +1,49 @@
/*
* Copyright (C) 2005-2008 Team XBMC
* http://www.xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with XBMC; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#ifndef _OMX_THREAD_H_
#define _OMX_THREAD_H_
#include <pthread.h>
class OMXThread
{
protected:
pthread_attr_t m_tattr;
struct sched_param m_sched_param;
pthread_mutex_t m_lock;
pthread_t m_thread;
volatile bool m_running;
volatile bool m_bStop;
private:
static void *Run(void *arg);
public:
OMXThread();
~OMXThread();
bool Create();
virtual void Process() = 0;
bool Running();
pthread_t ThreadHandle();
bool StopThread();
void Lock();
void UnLock();
};
#endif

1090
OMXVideo.cpp Normal file

File diff suppressed because it is too large Load diff

106
OMXVideo.h Normal file
View file

@ -0,0 +1,106 @@
#pragma once
/*
* Copyright (C) 2010 Team XBMC
* http://www.xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with XBMC; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#if defined(HAVE_OMXLIB)
#include "OMXCore.h"
#include "OMXStreamInfo.h"
#include <IL/OMX_Video.h>
#include "BitstreamConverter.h"
#include "OMXClock.h"
#include "OMXReader.h"
#include "guilib/Geometry.h"
#define VIDEO_BUFFERS 60
#define CLASSNAME "COMXVideo"
class DllAvUtil;
class DllAvFormat;
class COMXVideo
{
public:
COMXVideo();
~COMXVideo();
// Required overrides
bool SendDecoderConfig();
bool Open(COMXStreamInfo &hints, OMXClock *clock, bool deinterlace = false, bool hdmi_clock_sync = false);
void Close(void);
unsigned int GetFreeSpace();
unsigned int GetSize();
OMXPacket *GetText();
int DecodeText(uint8_t *pData, int iSize, double dts, double pts);
int Decode(uint8_t *pData, int iSize, double dts, double pts);
void Reset(void);
void SetDropState(bool bDrop);
bool Pause();
bool Resume();
CStdString GetDecoderName() { return m_video_codec_name; };
void SetVideoRect(const CRect& SrcRect, const CRect& DestRect);
int GetInputBufferSize();
void WaitCompletion();
protected:
// Video format
bool m_drop_state;
unsigned int m_decoded_width;
unsigned int m_decoded_height;
OMX_VIDEO_CODINGTYPE m_codingType;
COMXCoreComponent m_omx_text;
COMXCoreComponent m_omx_decoder;
COMXCoreComponent m_omx_render;
COMXCoreComponent m_omx_sched;
COMXCoreComponent m_omx_image_fx;
COMXCoreComponent *m_omx_clock;
OMXClock *m_av_clock;
COMXCoreTunel m_omx_tunnel_text;
COMXCoreTunel m_omx_tunnel_decoder;
COMXCoreTunel m_omx_tunnel_clock;
COMXCoreTunel m_omx_tunnel_sched;
COMXCoreTunel m_omx_tunnel_image_fx;
bool m_is_open;
bool m_Pause;
bool m_setStartTime;
uint8_t *m_extradata;
int m_extrasize;
CBitstreamConverter *m_converter;
bool m_video_convert;
CStdString m_video_codec_name;
bool m_deinterlace;
bool m_hdmi_clock_sync;
bool m_first_frame;
bool m_first_text;
};
#endif

65
RBP.h Normal file
View file

@ -0,0 +1,65 @@
#pragma once
/*
* Copyright (C) 2005-2009 Team XBMC
* http://www.xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with XBMC; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
/*
#define _HAVE_SBRK 1
#define HAVE_CMAKE_CONFIG 1
#define _REENTRANT 1
#ifndef VCHI_BULK_ALIGN
#define VCHI_BULK_ALIGN 1
#endif
#ifndef VCHI_BULK_GRANULARITY
#define VCHI_BULK_GRANULARITY 1
#endif
*/
//#define OMX_SKIP64BIT
#ifndef USE_VCHIQ_ARM
#define USE_VCHIQ_ARM
#endif
#ifndef __VIDEOCORE4__
#define __VIDEOCORE4__
#endif
#ifndef HAVE_VMCS_CONFIG
#define HAVE_VMCS_CONFIG
#endif
#ifndef HAVE_LIBBCM_HOST
#define HAVE_LIBBCM_HOST
#endif
#include "DllBCM.h"
class CRBP
{
public:
CRBP();
~CRBP();
bool Initialize();
void Deinitialize();
private:
DllBcmHost *m_DllBcmHost;
bool m_initialized;
};
extern CRBP g_RBP;

45
README Normal file
View file

@ -0,0 +1,45 @@
What is it :
omxplayer is a commandline OMX player for the Rasipberry PI.
It was developed as a testbed for the XBMC Raspberry PI implementation
and is quite handy to use standalone.
Using it :
Usage: omxplayer [OPTIONS] [FILE]
Options :
-h / --help print this help
-a / --alang language audio language : e.g. ger
-n / --aidx index audio stream index : e.g. 1
-o / --adev device audio out device : e.g. hdmi/local
-i / --info dump stream format and exit
-s / --stats pts and buffer stats
-p / --passthrough audio passthrough
-d / --deinterlace deinterlacing
-w / --hw hw audio decoding
-3 / --3d switch tv into 3d mode
-y / --hdmiclocksync adjust display refresh rate to match video
-t / --sid index show subtitle with index
For example: ./omxplayer -p -o hdmi test.mkv
Compiling :
You need the content of your sdcard somewhere mounted or copied.
There might be development headers to install on the running PI system
for the crosscompiling.
Edit Makefile.include and change the settings according your locations.
You can also compile it on the PI the native way ;)
Run :
make ffmpeg
make
make dist
Installing :
copy over omxplayer-dist/* to the PI /

43
cores/IAudioCallback.h Normal file
View file

@ -0,0 +1,43 @@
// IAudioCallback.h: interface for the IAudioCallback class.
//
//////////////////////////////////////////////////////////////////////
#if !defined(AFX_IAUDIOCALLBACK_H__5A6AC7CF_C60E_45B9_8113_599F036FBBF8__INCLUDED_)
#define AFX_IAUDIOCALLBACK_H__5A6AC7CF_C60E_45B9_8113_599F036FBBF8__INCLUDED_
/*
* Copyright (C) 2005-2008 Team XBMC
* http://www.xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with XBMC; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
class IAudioCallback
{
public:
IAudioCallback() {};
virtual ~IAudioCallback() {};
virtual void OnInitialize(int iChannels, int iSamplesPerSec, int iBitsPerSample) = 0;
virtual void OnAudioData(const unsigned char* pAudioData, int iAudioDataLength) = 0;
};
#endif // !defined(AFX_IAUDIOCALLBACK_H__5A6AC7CF_C60E_45B9_8113_599F036FBBF8__INCLUDED_)

173
guilib/Geometry.h Normal file
View file

@ -0,0 +1,173 @@
/*
* Copyright (C) 2005-2008 Team XBMC
* http://www.xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with XBMC; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#pragma once
#ifdef __GNUC__
// under gcc, inline will only take place if optimizations are applied (-O). this will force inline even whith optimizations.
#define XBMC_FORCE_INLINE __attribute__((always_inline))
#else
#define XBMC_FORCE_INLINE
#endif
#include <algorithm>
class CPoint
{
public:
CPoint()
{
x = 0; y = 0;
};
CPoint(float a, float b)
{
x = a;
y = b;
};
CPoint operator+(const CPoint &point) const
{
CPoint ans;
ans.x = x + point.x;
ans.y = y + point.y;
return ans;
};
const CPoint &operator+=(const CPoint &point)
{
x += point.x;
y += point.y;
return *this;
};
CPoint operator-(const CPoint &point) const
{
CPoint ans;
ans.x = x - point.x;
ans.y = y - point.y;
return ans;
};
const CPoint &operator-=(const CPoint &point)
{
x -= point.x;
y -= point.y;
return *this;
};
float x, y;
};
class CRect
{
public:
CRect() { x1 = y1 = x2 = y2 = 0;};
CRect(float left, float top, float right, float bottom) { x1 = left; y1 = top; x2 = right; y2 = bottom; };
void SetRect(float left, float top, float right, float bottom) { x1 = left; y1 = top; x2 = right; y2 = bottom; };
bool PtInRect(const CPoint &point) const
{
if (x1 <= point.x && point.x <= x2 && y1 <= point.y && point.y <= y2)
return true;
return false;
};
inline const CRect &operator -=(const CPoint &point) XBMC_FORCE_INLINE
{
x1 -= point.x;
y1 -= point.y;
x2 -= point.x;
y2 -= point.y;
return *this;
};
inline const CRect &operator +=(const CPoint &point) XBMC_FORCE_INLINE
{
x1 += point.x;
y1 += point.y;
x2 += point.x;
y2 += point.y;
return *this;
};
const CRect &Intersect(const CRect &rect)
{
x1 = clamp_range(x1, rect.x1, rect.x2);
x2 = clamp_range(x2, rect.x1, rect.x2);
y1 = clamp_range(y1, rect.y1, rect.y2);
y2 = clamp_range(y2, rect.y1, rect.y2);
return *this;
};
const CRect &Union(const CRect &rect)
{
if (IsEmpty())
*this = rect;
else if (!rect.IsEmpty())
{
x1 = std::min(x1,rect.x1);
y1 = std::min(y1,rect.y1);
x2 = std::max(x2,rect.x2);
y2 = std::max(y2,rect.y2);
}
return *this;
};
inline bool IsEmpty() const XBMC_FORCE_INLINE
{
return (x2 - x1) * (y2 - y1) == 0;
};
inline float Width() const XBMC_FORCE_INLINE
{
return x2 - x1;
};
inline float Height() const XBMC_FORCE_INLINE
{
return y2 - y1;
};
inline float Area() const XBMC_FORCE_INLINE
{
return Width() * Height();
};
bool operator !=(const CRect &rect) const
{
if (x1 != rect.x1) return true;
if (x2 != rect.x2) return true;
if (y1 != rect.y1) return true;
if (y2 != rect.y2) return true;
return false;
};
float x1, y1, x2, y2;
private:
inline static float clamp_range(float x, float l, float h) XBMC_FORCE_INLINE
{
return (x > h) ? h : ((x < l) ? l : x);
}
};

50
linux/ConvUtils.h Normal file
View file

@ -0,0 +1,50 @@
#ifndef __CONV_UTILS__H__
#define __CONV_UTILS__H__
/*
* Copyright (C) 2005-2008 Team XBMC
* http://www.xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with XBMC; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#include "PlatformDefs.h" // UINT DWORD LPCSTR LPSTR LPBOOL ...
int WideCharToMultiByte(
UINT CodePage,
DWORD dwFlags,
LPCWSTR lpWideCharStr,
int cchWideChar,
LPSTR lpMultiByteStr,
int cbMultiByte,
LPCSTR lpDefaultChar,
LPBOOL lpUsedDefaultChar
);
int MultiByteToWideChar(
UINT CodePage,
DWORD dwFlags,
LPCSTR lpMultiByteStr,
int cbMultiByte,
LPWSTR lpWideCharStr,
int cchWideChar
);
DWORD GetLastError();
VOID SetLastError(DWORD dwErrCode);
#endif

678
linux/PlatformDefs.h Normal file
View file

@ -0,0 +1,678 @@
#ifndef __PLATFORM_DEFS_H__
#define __PLATFORM_DEFS_H__
/*
* Copyright (C) 2005-2008 Team XBMC
* http://www.xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with XBMC; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#ifdef _LINUX
#define LINE_ENDING "\n"
#ifndef _LARGEFILE64_SOURCE
#define _LARGEFILE64_SOURCE
#endif
#undef _FILE_OFFSET_BITS
#define _FILE_OFFSET_BITS 64
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <pthread.h>
#include <string.h>
#ifdef __APPLE__
#include <stdio.h>
#include <sys/sysctl.h>
#include <mach/mach.h>
#else
#include <sys/sysinfo.h>
#endif
#include <sys/time.h>
#include <time.h>
#endif
// do not move this, it will break osx build bad"
#ifdef HAS_SDL
#include <SDL/SDL.h>
#endif
#if defined(__ppc__) || defined(__powerpc__)
#define PIXEL_ASHIFT 0
#define PIXEL_RSHIFT 8
#define PIXEL_GSHIFT 16
#define PIXEL_BSHIFT 24
#define AMASK 0x000000ff
#define RMASK 0x0000ff00
#define GMASK 0x00ff0000
#define BMASK 0xff000000
#else
#define PIXEL_ASHIFT 24
#define PIXEL_RSHIFT 16
#define PIXEL_GSHIFT 8
#define PIXEL_BSHIFT 0
#define AMASK 0xff000000
#define RMASK 0x00ff0000
#define GMASK 0x0000ff00
#define BMASK 0x000000ff
#endif
#include <stdint.h>
#ifndef PRId64
#ifdef _MSC_VER
#define PRId64 "I64d"
#else
#if __WORDSIZE == 64
#define PRId64 "ld"
#else
#define PRId64 "lld"
#endif
#endif
#endif
#ifndef PRIu64
#ifdef _MSC_VER
#define PRIu64 "I64u"
#else
#if __WORDSIZE == 64
#define PRIu64 "lu"
#else
#define PRIu64 "llu"
#endif
#endif
#endif
#ifndef PRIx64
#ifdef _MSC_VER
#define PRIx64 "I64x"
#else
#if __WORDSIZE == 64
#define PRIx64 "lx"
#else
#define PRIx64 "llx"
#endif
#endif
#endif
#ifndef PRIdS
#define PRIdS "zd"
#endif
#ifndef PRIuS
#define PRIuS "zu"
#endif
#ifdef _LINUX
#define XXLog(a,b) printf("%s", (b))
#ifndef INSTALL_PATH
#define INSTALL_PATH "/usr/share/xbmc"
#endif
#ifndef BIN_INSTALL_PATH
#define BIN_INSTALL_PATH "/usr/lib/xbmc"
#endif
#define CONST const
#define FALSE 0
#define TRUE 1
#define _fdopen fdopen
#define _vsnprintf vsnprintf
#define _stricmp strcasecmp
#define stricmp strcasecmp
#define strcmpi strcasecmp
#define strnicmp strncasecmp
#define _atoi64(x) atoll(x)
#define CopyMemory(dst,src,size) memmove(dst, src, size)
#define ZeroMemory(dst,size) memset(dst, 0, size)
#define VOID void
#define byte unsigned char
#define __int8 char
#define __int16 short
#define __int32 int
#define __int64 long long
#define __uint64 unsigned long long
#if defined(__x86_64__) || defined(__powerpc__) || defined(__ppc__) || defined (__arm__) // should this be powerpc64 only?
#define __stdcall
#else /* !__x86_64__ */
#define __stdcall __attribute__((__stdcall__))
#endif /* __x86_64__ */
#define __cdecl
#define WINBASEAPI
#define NTAPI __stdcall
#define CALLBACK __stdcall
#define WINAPI __stdcall
#define WINAPIV __cdecl
#ifndef __APPLE__
#define APIENTRY WINAPI
#else
#define APIENTRY
#endif
#define APIPRIVATE __stdcall
#define IN
#define OUT
#define OPTIONAL
#define _declspec(X)
#define __declspec(X)
#define __try try
#define EXCEPTION_EXECUTE_HANDLER ...
//NOTE: dont try to define __except because it breaks g++ (already uses it).
typedef pthread_t ThreadIdentifier;
struct CXHandle; // forward declaration
typedef CXHandle* HANDLE;
typedef void* HINSTANCE;
typedef void* HMODULE;
typedef unsigned int DWORD;
typedef unsigned short WORD;
typedef unsigned char BYTE;
typedef char CHAR;
typedef unsigned char UCHAR;
typedef wchar_t WCHAR;
typedef int BOOL;
typedef BYTE BOOLEAN;
typedef short SHORT;
typedef unsigned short USHORT;
typedef int INT;
typedef unsigned int UINT;
// typedef int INT32; // unused; must match Xmd.h but why bother
typedef unsigned int UINT32;
typedef long long INT64;
typedef unsigned long long UINT64;
typedef long LONG;
typedef long long LONGLONG;
typedef unsigned long ULONG;
typedef float FLOAT;
typedef size_t SIZE_T;
typedef void* PVOID;
typedef void* LPVOID;
//typedef PVOID HANDLE;
#define INVALID_HANDLE_VALUE ((HANDLE)~0U)
typedef HANDLE HDC;
typedef void* HWND;
typedef LONG HRESULT;
typedef BYTE* LPBYTE;
typedef DWORD* LPDWORD;
typedef CONST CHAR* LPCSTR;
typedef CONST WCHAR* LPCWSTR;
typedef CHAR* LPTSTR;
typedef WCHAR *PWSTR, *LPWSTR, *NWPSTR;
typedef CHAR *PSTR, *LPSTR, *NPSTR;
typedef LONG *PLONG, *LPLONG;
#ifdef UNICODE
typedef LPCWSTR LPCTSTR;
#else
typedef LPCSTR LPCTSTR;
#endif
typedef unsigned __int64 ULONGLONG;
typedef long LONG_PTR;
typedef unsigned long ULONG_PTR;
typedef ULONG_PTR DWORD_PTR;
typedef __int64 __time64_t;
typedef intptr_t (*FARPROC)(void);
#define MAXWORD 0xffff
#define MAXDWORD 0xffffffff
typedef DWORD LCID;
typedef WORD* LPWORD;
typedef BOOL* LPBOOL;
typedef CHAR* LPCHAR;
typedef CHAR* PCHAR;
typedef const void* LPCVOID;
typedef union _LARGE_INTEGER
{
struct {
DWORD LowPart;
int32_t HighPart;
} u;
LONGLONG QuadPart;
} LARGE_INTEGER, *PLARGE_INTEGER;
typedef union _ULARGE_INTEGER {
struct {
DWORD LowPart;
DWORD HighPart;
} u;
ULONGLONG QuadPart;
} ULARGE_INTEGER, *PULARGE_INTEGER;
#define MAKELONG(low,high) ((LONG)(((WORD)((DWORD_PTR)(low) & 0xFFFF)) | ((DWORD)((WORD)((DWORD_PTR)(high) & 0xFFFF))) << 16))
LONGLONG Int32x32To64(LONG Multiplier, LONG Multiplicand);
void OutputDebugString(LPCTSTR lpOuputString);
// Date / Time
typedef struct _SYSTEMTIME
{
WORD wYear;
WORD wMonth;
WORD wDayOfWeek;
WORD wDay;
WORD wHour;
WORD wMinute;
WORD wSecond;
WORD wMilliseconds;
} SYSTEMTIME, *PSYSTEMTIME, *LPSYSTEMTIME;
typedef struct _TIME_ZONE_INFORMATION {
LONG Bias;
WCHAR StandardName[32];
SYSTEMTIME StandardDate;
LONG StandardBias;
WCHAR DaylightName[32];
SYSTEMTIME DaylightDate;
LONG DaylightBias;
} TIME_ZONE_INFORMATION, *PTIME_ZONE_INFORMATION, *LPTIME_ZONE_INFORMATION;
#define TIME_ZONE_ID_INVALID ((DWORD)0xFFFFFFFF)
#define TIME_ZONE_ID_UNKNOWN 0
#define TIME_ZONE_ID_STANDARD 1
#define TIME_ZONE_ID_DAYLIGHT 2
// Thread
#define THREAD_BASE_PRIORITY_LOWRT 15
#define THREAD_BASE_PRIORITY_MAX 2
#define THREAD_BASE_PRIORITY_MIN -2
#define THREAD_BASE_PRIORITY_IDLE -15
#define THREAD_PRIORITY_LOWEST THREAD_BASE_PRIORITY_MIN
#define THREAD_PRIORITY_BELOW_NORMAL (THREAD_PRIORITY_LOWEST+1)
#define THREAD_PRIORITY_NORMAL 0
#define THREAD_PRIORITY_HIGHEST THREAD_BASE_PRIORITY_MAX
#define THREAD_PRIORITY_ABOVE_NORMAL (THREAD_PRIORITY_HIGHEST-1)
#define THREAD_PRIORITY_ERROR_RETURN (0x7fffffff)
#define THREAD_PRIORITY_TIME_CRITICAL THREAD_BASE_PRIORITY_LOWRT
#define THREAD_PRIORITY_IDLE THREAD_BASE_PRIORITY_IDLE
// Network
#define SOCKADDR_IN struct sockaddr_in
#define IN_ADDR struct in_addr
#define SOCKET_ERROR (-1)
#define INVALID_SOCKET (~0)
#define closesocket(s) close(s)
#define ioctlsocket(s, f, v) ioctl(s, f, v)
#define WSAGetLastError() (errno)
#define WSASetLastError(e) (errno = e)
#define WSAECONNRESET ECONNRESET
#define WSAHOST_NOT_FOUND ENOENT
#define WSAETIMEDOUT ETIMEDOUT
#define WSAEADDRINUSE EADDRINUSE
#define WSAECANCELLED EINTR
#define WSAECONNREFUSED ECONNREFUSED
#define WSAECONNABORTED ECONNABORTED
#define WSAETIMEDOUT ETIMEDOUT
typedef int SOCKET;
// Thread
typedef int (*LPTHREAD_START_ROUTINE)(void *);
// File
#define O_BINARY 0
#define O_TEXT 0
#define _O_TRUNC O_TRUNC
#define _O_RDONLY O_RDONLY
#define _O_WRONLY O_WRONLY
#define _off_t off_t
#if defined(__APPLE__)
#include <sched.h>
#include <AvailabilityMacros.h>
typedef int64_t off64_t;
typedef off_t __off_t;
typedef off64_t __off64_t;
typedef fpos_t fpos64_t;
#if (MAC_OS_X_VERSION_MAX_ALLOWED < 1050)
#define __stat64 stat
#define stat64 stat
#define statfs64 statfs
#define fstat64 fstat
#elif defined(__arm__)
#define __stat64 stat
#define stat64 stat
#define statfs64 statfs
#define fstat64 fstat
#else
#define fstat64 fstat
#endif
#else
#define __stat64 stat64
#endif
struct _stati64 {
dev_t st_dev;
ino_t st_ino;
unsigned short st_mode;
short st_nlink;
short st_uid;
short st_gid;
dev_t st_rdev;
__int64 st_size;
time_t _st_atime;
time_t _st_mtime;
time_t _st_ctime;
};
typedef struct _FILETIME
{
DWORD dwLowDateTime;
DWORD dwHighDateTime;
} FILETIME, *PFILETIME, *LPFILETIME;
typedef struct _WIN32_FIND_DATA
{
DWORD dwFileAttributes;
FILETIME ftCreationTime;
FILETIME ftLastAccessTime;
FILETIME ftLastWriteTime;
DWORD nFileSizeHigh;
DWORD nFileSizeLow;
DWORD dwReserved0;
DWORD dwReserved1;
CHAR cFileName[260];
CHAR cAlternateFileName[14];
} WIN32_FIND_DATA, *PWIN32_FIND_DATA, *LPWIN32_FIND_DATA;
#define LPWIN32_FIND_DATAA LPWIN32_FIND_DATA
#define FILE_ATTRIBUTE_DIRECTORY 0x00000010
typedef struct _SECURITY_ATTRIBUTES {
DWORD nLength;
LPVOID lpSecurityDescriptor;
BOOL bInheritHandle;
} SECURITY_ATTRIBUTES, *PSECURITY_ATTRIBUTES, *LPSECURITY_ATTRIBUTES;
#define FILE_BEGIN 0
#define FILE_CURRENT 1
#define FILE_END 2
#define _S_IFREG S_IFREG
#define _S_IFDIR S_IFDIR
#define MAX_PATH PATH_MAX
#define _stat stat
// Memory
typedef struct _MEMORYSTATUS
{
DWORD dwLength;
DWORD dwMemoryLoad;
uint64_t dwTotalPhys;
uint64_t dwAvailPhys;
uint64_t dwTotalPageFile;
uint64_t dwAvailPageFile;
uint64_t dwTotalVirtual;
uint64_t dwAvailVirtual;
} MEMORYSTATUS, *LPMEMORYSTATUS;
// Common HRESULT values
#ifndef NOERROR
#define NOERROR (0L)
#endif
#ifndef S_OK
#define S_OK (0L)
#endif
#ifndef E_FAIL
#define E_FAIL (0x80004005L)
#endif
#ifndef E_OUTOFMEMORY
#define E_OUTOFMEMORY (0x8007000EL)
#endif
#define FAILED(Status) ((HRESULT)(Status)<0)
// Basic D3D stuff
typedef struct _RECT {
LONG left;
LONG top;
LONG right;
LONG bottom;
} RECT, *PRECT;
typedef DWORD D3DCOLOR;
typedef enum _D3DFORMAT
{
D3DFMT_A8R8G8B8 = 0x00000006,
D3DFMT_DXT1 = 0x0000000C,
D3DFMT_DXT2 = 0x0000000E,
D3DFMT_DXT4 = 0x0000000F,
D3DFMT_UNKNOWN = 0xFFFFFFFF
} D3DFORMAT;
typedef enum D3DRESOURCETYPE
{
D3DRTYPE_SURFACE = 1,
D3DRTYPE_VOLUME = 2,
D3DRTYPE_TEXTURE = 3,
D3DRTYPE_VOLUMETEXTURE = 4,
D3DRTYPE_CubeTexture = 5,
D3DRTYPE_VERTEXBUFFER = 6,
D3DRTYPE_INDEXBUFFER = 7,
D3DRTYPE_FORCE_DWORD = 0x7fffffff
} D3DRESOURCETYPE, *LPD3DRESOURCETYPE;
typedef enum D3DXIMAGE_FILEFORMAT
{
D3DXIFF_BMP = 0,
D3DXIFF_JPG = 1,
D3DXIFF_TGA = 2,
D3DXIFF_PNG = 3,
D3DXIFF_DDS = 4,
D3DXIFF_PPM = 5,
D3DXIFF_DIB = 6,
D3DXIFF_HDR = 7,
D3DXIFF_PFM = 8,
D3DXIFF_FORCE_DWORD = 0x7fffffff
} D3DXIMAGE_FILEFORMAT, *LPD3DXIMAGE_FILEFORMAT;
typedef struct D3DXIMAGE_INFO {
UINT Width;
UINT Height;
UINT Depth;
UINT MipLevels;
D3DFORMAT Format;
D3DRESOURCETYPE ResourceType;
D3DXIMAGE_FILEFORMAT ImageFileFormat;
} D3DXIMAGE_INFO, *LPD3DXIMAGE_INFO;
typedef struct _D3DPRESENT_PARAMETERS_
{
UINT BackBufferWidth;
UINT BackBufferHeight;
D3DFORMAT BackBufferFormat;
UINT BackBufferCount;
//D3DMULTISAMPLE_TYPE MultiSampleType;
//D3DSWAPEFFECT SwapEffect;
//HWND hDeviceWindow;
BOOL Windowed;
BOOL EnableAutoDepthStencil;
D3DFORMAT AutoDepthStencilFormat;
DWORD Flags;
UINT FullScreen_RefreshRateInHz;
UINT FullScreen_PresentationInterval;
//D3DSurface *BufferSurfaces[3];
//D3DSurface *DepthStencilSurface;
} D3DPRESENT_PARAMETERS;
typedef enum D3DPRIMITIVETYPE
{
D3DPT_POINTLIST = 1,
D3DPT_LINELIST = 2,
D3DPT_LINESTRIP = 3,
D3DPT_TRIANGLELIST = 4,
D3DPT_TRIANGLESTRIP = 5,
D3DPT_TRIANGLEFAN = 6,
D3DPT_FORCE_DWORD = 0x7fffffff
} D3DPRIMITIVETYPE, *LPD3DPRIMITIVETYPE;
typedef struct _D3DMATRIX {
union {
struct {
float _11, _12, _13, _14;
float _21, _22, _23, _24;
float _31, _32, _33, _34;
float _41, _42, _43, _44;
} u;
float m[4][4];
};
} D3DMATRIX;
// Misc stuff found in the code, not really important
#define PAGE_READONLY 0x02
#define PAGE_READWRITE 0x04
#define MAXULONG_PTR ((ULONG) 0xffffffff)
// CreateFile defines
#define FILE_FLAG_WRITE_THROUGH 0x80000000
#define FILE_FLAG_OVERLAPPED 0x40000000
#define FILE_FLAG_NO_BUFFERING 0x20000000
#define FILE_FLAG_RANDOM_ACCESS 0x10000000
#define FILE_FLAG_SEQUENTIAL_SCAN 0x08000000
#define FILE_FLAG_DELETE_ON_CLOSE 0x04000000
#define FILE_FLAG_BACKUP_SEMANTICS 0x02000000
#define FILE_FLAG_POSIX_SEMANTICS 0x01000000
#define FILE_FLAG_OPEN_REPARSE_POINT 0x00200000
#define FILE_FLAG_OPEN_NO_RECALL 0x00100000
#define FILE_FLAG_FIRST_PIPE_INSTANCE 0x00080000
#define CREATE_NEW 1
#define CREATE_ALWAYS 2
#define OPEN_EXISTING 3
#define OPEN_ALWAYS 4
#define TRUNCATE_EXISTING 5
#define FILE_ATTRIBUTE_NORMAL 0x00000080
#define FILE_ATTRIBUTE_READONLY 0x00000001
#define FILE_ATTRIBUTE_HIDDEN 0x00000002
#define FILE_ATTRIBUTE_SYSTEM 0x00000004
#define FILE_ATTRIBUTE_DIRECTORY 0x00000010
#define FILE_READ_DATA ( 0x0001 )
#define FILE_WRITE_DATA ( 0x0002 )
#define FILE_APPEND_DATA ( 0x0004 )
#define GENERIC_READ FILE_READ_DATA
#define GENERIC_WRITE FILE_WRITE_DATA
#define FILE_SHARE_READ 0x00000001
#define FILE_SHARE_WRITE 0x00000002
#define FILE_SHARE_DELETE 0x00000004
// String
char *itoa(int i, char *a, int r);
void strlwr(char* string);
void strupr(char* string);
// Audio stuff
typedef struct tWAVEFORMATEX
{
WORD wFormatTag;
WORD nChannels;
DWORD nSamplesPerSec;
DWORD nAvgBytesPerSec;
WORD nBlockAlign;
WORD wBitsPerSample;
WORD cbSize;
} __attribute__((__packed__)) WAVEFORMATEX, *PWAVEFORMATEX, *LPWAVEFORMATEX;
#define WAVE_FORMAT_UNKNOWN 0x0000
#define WAVE_FORMAT_PCM 0x0001
#define WAVE_FORMAT_ADPCM 0x0002
#define WAVE_FORMAT_IEEE_FLOAT 0x0003
#define WAVE_FORMAT_EXTENSIBLE 0xFFFE
#define SPEAKER_FRONT_LEFT 0x00001
#define SPEAKER_FRONT_RIGHT 0x00002
#define SPEAKER_FRONT_CENTER 0x00004
#define SPEAKER_LOW_FREQUENCY 0x00008
#define SPEAKER_BACK_LEFT 0x00010
#define SPEAKER_BACK_RIGHT 0x00020
#define SPEAKER_FRONT_LEFT_OF_CENTER 0x00040
#define SPEAKER_FRONT_RIGHT_OF_CENTER 0x00080
#define SPEAKER_BACK_CENTER 0x00100
#define SPEAKER_SIDE_LEFT 0x00200
#define SPEAKER_SIDE_RIGHT 0x00400
#define SPEAKER_TOP_CENTER 0x00800
#define SPEAKER_TOP_FRONT_LEFT 0x01000
#define SPEAKER_TOP_FRONT_CENTER 0x02000
#define SPEAKER_TOP_FRONT_RIGHT 0x04000
#define SPEAKER_TOP_BACK_LEFT 0x08000
#define SPEAKER_TOP_BACK_CENTER 0x10000
#define SPEAKER_TOP_BACK_RIGHT 0x20000
typedef struct tGUID
{
DWORD Data1;
WORD Data2, Data3;
BYTE Data4[8];
} __attribute__((__packed__)) GUID;
static const GUID KSDATAFORMAT_SUBTYPE_UNKNOWN = {
WAVE_FORMAT_UNKNOWN,
0x0000, 0x0000,
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
};
static const GUID KSDATAFORMAT_SUBTYPE_PCM = {
WAVE_FORMAT_PCM,
0x0000, 0x0010,
{0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
};
static const GUID KSDATAFORMAT_SUBTYPE_IEEE_FLOAT = {
WAVE_FORMAT_IEEE_FLOAT,
0x0000, 0x0010,
{0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
};
typedef struct tWAVEFORMATEXTENSIBLE
{
WAVEFORMATEX Format;
union
{
WORD wValidBitsPerSample;
WORD wSamplesPerBlock;
WORD wReserved;
} Samples;
DWORD dwChannelMask;
GUID SubFormat;
} __attribute__((__packed__)) WAVEFORMATEXTENSIBLE;
#endif
#endif //__PLATFORM_DEFS_H__

36
linux/PlatformInclude.h Normal file
View file

@ -0,0 +1,36 @@
#ifndef __PLATFORM_INCLUDE__H__
#define __PLATFORM_INCLUDE__H__
/*
* Copyright (C) 2005-2008 Team XBMC
* http://www.xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with XBMC; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#include "PlatformDefs.h"
#include "XHandlePublic.h"
#include "XFileUtils.h"
#include "XSyncUtils.h"
#include "XEventUtils.h"
#include "XTimeUtils.h"
#include "XThreadUtils.h"
#include "XMemUtils.h"
#include "ConvUtils.h"
#endif

58
linux/RBP.cpp Normal file
View file

@ -0,0 +1,58 @@
/*
* Copyright (C) 2005-2009 Team XBMC
* http://www.xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with XBMC; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#include "RBP.h"
#include "utils/log.h"
#define CLASSNAME "CRBP"
CRBP::CRBP()
{
m_initialized = false;
m_DllBcmHost = new DllBcmHost();
}
CRBP::~CRBP()
{
Deinitialize();
delete m_DllBcmHost;
}
bool CRBP::Initialize()
{
m_initialized = m_DllBcmHost->Load();
if(!m_initialized)
return false;
m_DllBcmHost->bcm_host_init();
return true;
}
void CRBP::Deinitialize()
{
m_DllBcmHost->bcm_host_deinit();
if(m_initialized)
m_DllBcmHost->Unload();
m_initialized = false;
}

61
linux/RBP.h Normal file
View file

@ -0,0 +1,61 @@
#pragma once
/*
* Copyright (C) 2005-2009 Team XBMC
* http://www.xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with XBMC; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
/*
#define _HAVE_SBRK 1
#define HAVE_CMAKE_CONFIG 1
#define _REENTRANT 1
#ifndef VCHI_BULK_ALIGN
#define VCHI_BULK_ALIGN 1
#endif
#ifndef VCHI_BULK_GRANULARITY
#define VCHI_BULK_GRANULARITY 1
#endif
*/
//#define OMX_SKIP64BIT
#ifndef USE_VCHIQ_ARM
#define USE_VCHIQ_ARM
#endif
#ifndef __VIDEOCORE4__
#define __VIDEOCORE4__
#endif
#ifndef HAVE_VMCS_CONFIG
#define HAVE_VMCS_CONFIG
#endif
#include "DllBCM.h"
class CRBP
{
public:
CRBP();
~CRBP();
bool Initialize();
void Deinitialize();
private:
DllBcmHost *m_DllBcmHost;
bool m_initialized;
};
extern CRBP g_RBP;

52
linux/XMemUtils.cpp Normal file
View file

@ -0,0 +1,52 @@
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
/*
* Copyright (C) 2005-2008 Team XBMC
* http://www.xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with XBMC; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#include "XMemUtils.h"
#undef ALIGN
#define ALIGN(value, alignment) (((value)+(alignment-1))&~(alignment-1))
// aligned memory allocation.
// in order to do so - we alloc extra space and store the original allocation in it (so that we can free later on).
// the returned address will be the nearest alligned address within the space allocated.
void *_aligned_malloc(size_t s, size_t alignTo) {
char *pFull = (char*)malloc(s + alignTo + sizeof(char *));
char *pAlligned = (char *)ALIGN(((unsigned long)pFull + sizeof(char *)), alignTo);
*(char **)(pAlligned - sizeof(char*)) = pFull;
return(pAlligned);
}
void _aligned_free(void *p) {
if (!p)
return;
char *pFull = *(char **)(((char *)p) - sizeof(char *));
free(pFull);
}

37
linux/XMemUtils.d Normal file
View file

@ -0,0 +1,37 @@
linux/XMemUtils.o: linux/XMemUtils.cpp \
/usr/local/bcm-gcc/bin/../arm-bcm2708-linux-gnueabi//sys-root/usr/include/stdlib.h \
/usr/local/bcm-gcc/bin/../arm-bcm2708-linux-gnueabi//sys-root/usr/include/features.h \
/usr/local/bcm-gcc/bin/../arm-bcm2708-linux-gnueabi//sys-root/usr/include/sys/cdefs.h \
/usr/local/bcm-gcc/bin/../arm-bcm2708-linux-gnueabi//sys-root/usr/include/bits/wordsize.h \
/usr/local/bcm-gcc/bin/../arm-bcm2708-linux-gnueabi//sys-root/usr/include/gnu/stubs.h \
/usr/local/bcm-gcc/bin/../lib/gcc/arm-bcm2708-linux-gnueabi/4.5.1/include/stddef.h \
/usr/local/bcm-gcc/bin/../arm-bcm2708-linux-gnueabi//sys-root/usr/include/bits/waitflags.h \
/usr/local/bcm-gcc/bin/../arm-bcm2708-linux-gnueabi//sys-root/usr/include/bits/waitstatus.h \
/usr/local/bcm-gcc/bin/../arm-bcm2708-linux-gnueabi//sys-root/usr/include/endian.h \
/usr/local/bcm-gcc/bin/../arm-bcm2708-linux-gnueabi//sys-root/usr/include/bits/endian.h \
/usr/local/bcm-gcc/bin/../arm-bcm2708-linux-gnueabi//sys-root/usr/include/bits/byteswap.h \
/usr/local/bcm-gcc/bin/../arm-bcm2708-linux-gnueabi//sys-root/usr/include/xlocale.h \
/usr/local/bcm-gcc/bin/../arm-bcm2708-linux-gnueabi//sys-root/usr/include/sys/types.h \
/usr/local/bcm-gcc/bin/../arm-bcm2708-linux-gnueabi//sys-root/usr/include/bits/types.h \
/usr/local/bcm-gcc/bin/../arm-bcm2708-linux-gnueabi//sys-root/usr/include/bits/typesizes.h \
/usr/local/bcm-gcc/bin/../arm-bcm2708-linux-gnueabi//sys-root/usr/include/time.h \
/usr/local/bcm-gcc/bin/../arm-bcm2708-linux-gnueabi//sys-root/usr/include/sys/select.h \
/usr/local/bcm-gcc/bin/../arm-bcm2708-linux-gnueabi//sys-root/usr/include/bits/select.h \
/usr/local/bcm-gcc/bin/../arm-bcm2708-linux-gnueabi//sys-root/usr/include/bits/sigset.h \
/usr/local/bcm-gcc/bin/../arm-bcm2708-linux-gnueabi//sys-root/usr/include/bits/time.h \
/usr/local/bcm-gcc/bin/../arm-bcm2708-linux-gnueabi//sys-root/usr/include/sys/sysmacros.h \
/usr/local/bcm-gcc/bin/../arm-bcm2708-linux-gnueabi//sys-root/usr/include/bits/pthreadtypes.h \
/usr/local/bcm-gcc/bin/../arm-bcm2708-linux-gnueabi//sys-root/usr/include/alloca.h \
/usr/local/bcm-gcc/bin/../arm-bcm2708-linux-gnueabi//sys-root/usr/include/stdio.h \
/usr/local/bcm-gcc/bin/../arm-bcm2708-linux-gnueabi//sys-root/usr/include/libio.h \
/usr/local/bcm-gcc/bin/../arm-bcm2708-linux-gnueabi//sys-root/usr/include/_G_config.h \
/usr/local/bcm-gcc/bin/../arm-bcm2708-linux-gnueabi//sys-root/usr/include/wchar.h \
/usr/local/bcm-gcc/bin/../lib/gcc/arm-bcm2708-linux-gnueabi/4.5.1/include/stdarg.h \
/usr/local/bcm-gcc/bin/../arm-bcm2708-linux-gnueabi//sys-root/usr/include/bits/stdio_lim.h \
/usr/local/bcm-gcc/bin/../arm-bcm2708-linux-gnueabi//sys-root/usr/include/bits/sys_errlist.h \
/usr/local/bcm-gcc/bin/../arm-bcm2708-linux-gnueabi//sys-root/usr/include/unistd.h \
/usr/local/bcm-gcc/bin/../arm-bcm2708-linux-gnueabi//sys-root/usr/include/bits/posix_opt.h \
/usr/local/bcm-gcc/bin/../arm-bcm2708-linux-gnueabi//sys-root/usr/include/bits/environments.h \
/usr/local/bcm-gcc/bin/../arm-bcm2708-linux-gnueabi//sys-root/usr/include/bits/confname.h \
/usr/local/bcm-gcc/bin/../arm-bcm2708-linux-gnueabi//sys-root/usr/include/getopt.h \
linux/XMemUtils.h

31
linux/XMemUtils.h Normal file
View file

@ -0,0 +1,31 @@
#ifndef __XMEMUTILS__H__
#define __XMEMUTILS__H__
/*
* Copyright (C) 2005-2008 Team XBMC
* http://www.xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with XBMC; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
// aligned memory allocation and free. memory returned will be aligned to "alignTo" bytes.
// this is a linux (actually platfom free) implementation of the win32 CRT methods _aligned_malloc and _aligned_free.
void *_aligned_malloc(size_t s, size_t alignTo);
void _aligned_free(void *p) ;
#endif

44
linux/XSyncUtils.h Normal file
View file

@ -0,0 +1,44 @@
#ifndef __X_SYNC_UTILS_
#define __X_SYNC_UTILS_
/*
* Copyright (C) 2005-2008 Team XBMC
* http://www.xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with XBMC; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#include "PlatformDefs.h"
#include "XHandlePublic.h"
#ifdef _LINUX
#define STATUS_WAIT_0 ((DWORD )0x00000000L)
#define WAIT_FAILED ((DWORD)0xFFFFFFFF)
#define WAIT_OBJECT_0 ((STATUS_WAIT_0 ) + 0 )
#define WAIT_TIMEOUT 258L
#define INFINITE 0xFFFFFFFF
#define STATUS_ABANDONED_WAIT_0 0x00000080
#define WAIT_ABANDONED ((STATUS_ABANDONED_WAIT_0 ) + 0 )
#define WAIT_ABANDONED_0 ((STATUS_ABANDONED_WAIT_0 ) + 0 )
void GlobalMemoryStatus(LPMEMORYSTATUS lpBuffer);
#endif
#endif

28
linux/stat_utf8.h Normal file
View file

@ -0,0 +1,28 @@
/*
* Copyright (C) 2005-2011 Team XBMC
* http://www.xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with XBMC; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#ifndef STAT_UTF8_H__
#define STAT_UTF8_H__
#define stat64_utf8 stat64
#endif //STAT_UTF8_H__

32
linux/stdio_utf8.h Normal file
View file

@ -0,0 +1,32 @@
/*
* Copyright (C) 2005-2011 Team XBMC
* http://www.xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with XBMC; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#ifndef STDIO_UTF8_H__
#define STDIO_UTF8_H__
#include <cstdio>
#define remove_utf8 remove
#define rename_utf8 rename
#define fopen64_utf8 fopen
#endif // STDIO_UTF8_H__

34
omxplayer Executable file
View file

@ -0,0 +1,34 @@
#!/bin/sh
#mount -t nfs -o rsize=32768,wsize=32768,intr 192.168.10.1:/data/video /media
OMXPLAYER="./omxplayer.bin"
FBSET="/usr/sbin/fbset"
if [ -e /usr/bin/omxplayer.bin ]; then
OMXPLAYER="/usr/bin/omxplayer.bin"
fi
if [ -e /usr/lib/omxplayer ]; then
export LD_LIBRARY_PATH=/opt/vc/lib:/usr/lib/omxplayer:$LD_LIBRARY_PATH
else
export LD_LIBRARY_PATH=$PWD/ffmpeg_compiled/usr/local/lib:/opt/vc/lib:$LD_LIBRARY_PATH
fi
XRES=1920
YRES=1080
XRES=1600
YRES=900
if [ -e $FBSET ]; then
echo 0 > /sys/class/vtconsole/vtcon1/bind
fbset -xres 1 -yres 1
fi
./omxplayer.bin "$@"
if [ -e $FBSET ]; then
fbset -xres ${XRES} -yres ${YRES}
echo 1 > /sys/class/vtconsole/vtcon1/bind
fi

730
omxplayer.cpp Normal file
View file

@ -0,0 +1,730 @@
/*
*
* Copyright (C) 2012 Edgar Hucek
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <stdint.h>
#include <termios.h>
#include <sys/mman.h>
#include <linux/fb.h>
#include <sys/ioctl.h>
#include <getopt.h>
#define AV_NOWARN_DEPRECATED
extern "C" {
#include <libavformat/avformat.h>
#include <libavutil/avutil.h>
};
#include "OMXStreamInfo.h"
#include "utils/log.h"
#include "DllAvUtil.h"
#include "DllAvFormat.h"
#include "DllAvFilter.h"
#include "DllAvCodec.h"
#include "DllAvCore.h"
#include "linux/RBP.h"
#include "OMXVideo.h"
#include "OMXAudioCodecOMX.h"
#include "utils/PCMRemap.h"
#include "OMXClock.h"
#include "OMXAudio.h"
#include "OMXReader.h"
#include "OMXPlayerVideo.h"
#include "OMXPlayerAudio.h"
#include "DllOMX.h"
enum PCMChannels *m_pChannelMap = NULL;
unsigned int g_abort = false;
bool m_bMpeg = false;
bool m_passthrough = false;
bool m_Deinterlace = false;
bool m_HWDecode = false;
CStdString deviceString = "omx:local";
int m_use_hw_audio = false;
bool m_Pause = false;
OMXReader m_omx_reader;
int m_audio_index_use = -1;
bool m_buffer_empty = true;
bool m_thread_player = false;
int64_t m_audio_offset_ms = 0;
OMXClock *m_av_clock = NULL;
COMXStreamInfo m_hints_audio;
COMXStreamInfo m_hints_video;
OMXPacket *m_omx_pkt = NULL;
bool m_hdmi_clock_sync = false;
bool m_stop = false;
bool m_show_subtitle = false;
bool m_subtitle_index = 0;
DllBcmHost m_BcmHost;
OMXPlayerVideo m_player_video;
OMXPlayerAudio m_player_audio;
int m_tv_show_info = 0;
bool m_has_video = false;
bool m_has_audio = false;
bool m_has_subtitle = false;
enum{ERROR=-1,SUCCESS,ONEBYTE};
static struct termios orig_termios;
static void restore_termios (int status, void * arg)
{
tcsetattr(STDIN_FILENO, TCSANOW, &orig_termios);
}
void sig_handler(int s)
{
printf("strg-c catched\n");
g_abort = true;
}
void print_usage()
{
printf("Usage: omxplayer [OPTIONS] [FILE]\n");
printf("Options :\n");
printf(" -h / --help print this help\n");
printf(" -a / --alang language audio language : e.g. ger\n");
printf(" -n / --aidx index audio stream index : e.g. 1\n");
printf(" -o / --adev device audio out device : e.g. hdmi/local\n");
printf(" -i / --info dump stream format and exit\n");
printf(" -s / --stats pts and buffer stats\n");
printf(" -p / --passthrough audio passthrough\n");
printf(" -d / --deinterlace deinterlacing\n");
printf(" -w / --hw hw audio decoding\n");
printf(" -3 / --3d switch tv into 3d mode\n");
printf(" -y / --hdmiclocksync adjust display refresh rate to match video\n");
printf(" -t / --sid index show subtitle with index\n");
}
void SetSpeed(int iSpeed)
{
if(!m_av_clock)
return;
if(iSpeed < OMX_PLAYSPEED_PAUSE)
return;
m_omx_reader.SetSpeed(iSpeed);
if(m_av_clock->OMXPlaySpeed() != OMX_PLAYSPEED_PAUSE && iSpeed == OMX_PLAYSPEED_PAUSE)
m_Pause = true;
else if(m_av_clock->OMXPlaySpeed() == OMX_PLAYSPEED_PAUSE && iSpeed != OMX_PLAYSPEED_PAUSE)
m_Pause = false;
m_av_clock->OMXSpeed(iSpeed);
}
void FlushStreams()
{
if(m_av_clock)
m_av_clock->OMXPause();
if(m_has_video)
m_player_video.Flush();
if(m_has_audio)
m_player_audio.Flush();
if(m_omx_pkt)
{
m_omx_reader.FreePacket(m_omx_pkt);
m_omx_pkt = NULL;
}
if(m_av_clock)
{
m_av_clock->OMXReset();
m_av_clock->OMXResume();
}
}
int main(int argc, char *argv[])
{
struct termios new_termios;
tcgetattr(STDIN_FILENO, &orig_termios);
new_termios = orig_termios;
new_termios.c_lflag &= ~(ICANON | ECHO | ECHOCTL | ECHONL);
new_termios.c_cflag |= HUPCL;
new_termios.c_cc[VMIN] = 0;
CStdString last_sub = "";
tcsetattr(STDIN_FILENO, TCSANOW, &new_termios);
on_exit(restore_termios, &orig_termios);
CStdString m_filename;
double m_incr = 0;
CRBP g_RBP;
COMXCore g_OMX;
bool m_stats = false;
bool m_dump_format = false;
bool m_3d = false;
double startpts = 0;
TV_GET_STATE_RESP_T tv_state;
struct option longopts[] = {
{ "info", no_argument, NULL, 'i' },
{ "help", no_argument, NULL, 'h' },
{ "aidx", required_argument, NULL, 'n' },
{ "adev", required_argument, NULL, 'o' },
{ "stats", no_argument, NULL, 's' },
{ "passthrough", no_argument, NULL, 'p' },
{ "deinterlace", no_argument, NULL, 'd' },
{ "hw", no_argument, NULL, 'w' },
{ "3d", no_argument, NULL, '3' },
{ "hdmiclocksync", no_argument, NULL, 'y' },
{ "sid", required_argument, NULL, 't' },
{ 0, 0, 0, 0 }
};
int c;
while ((c = getopt_long(argc, argv, "wihn:o:cslpd3yt:", longopts, NULL)) != -1)
{
switch (c)
{
case 'y':
m_hdmi_clock_sync = true;
break;
case '3':
m_3d = true;
break;
case 'd':
m_Deinterlace = true;
break;
case 'w':
m_use_hw_audio = true;
break;
case 'p':
m_passthrough = true;
break;
case 's':
m_stats = true;
break;
case 'o':
deviceString = optarg;
if(deviceString != CStdString("local") && deviceString != CStdString("hdmi"))
{
print_usage();
return 0;
}
deviceString = "omx:" + deviceString;
break;
case 'i':
m_dump_format = true;
break;
case 't':
m_subtitle_index = atoi(optarg) - 1;
if(m_subtitle_index < 0)
m_subtitle_index = 0;
m_show_subtitle = true;
break;
case 'n':
m_audio_index_use = atoi(optarg) - 1;
if(m_audio_index_use < 0)
m_audio_index_use = 0;
break;
case 0:
break;
case 'h':
print_usage();
return 0;
break;
case ':':
return 0;
break;
default:
return 0;
break;
}
}
if (optind >= argc) {
print_usage();
return 0;
}
m_filename = argv[optind];
CLog::Init("./");
g_RBP.Initialize();
g_OMX.Initialize();
m_av_clock = new OMXClock();
m_thread_player = true;
if(!m_omx_reader.Open(m_filename.c_str(), m_dump_format))
goto do_exit;
if(m_dump_format)
goto do_exit;
m_bMpeg = m_omx_reader.IsMpegVideo();
m_has_video = m_omx_reader.VideoStreamCount();
m_has_audio = m_omx_reader.AudioStreamCount();
m_has_subtitle = m_omx_reader.SubtitleStreamCount();
if(!m_av_clock->OMXInitialize(m_has_video, m_has_audio))
goto do_exit;
if(m_hdmi_clock_sync && !m_av_clock->HDMIClockSync())
goto do_exit;
m_omx_reader.GetHints(OMXSTREAM_AUDIO, m_hints_audio);
m_omx_reader.GetHints(OMXSTREAM_VIDEO, m_hints_video);
if(m_audio_index_use != -1)
m_omx_reader.SetActiveStream(OMXSTREAM_AUDIO, m_audio_index_use);
if(m_has_video && !m_player_video.Open(m_hints_video, m_av_clock, m_Deinterlace, m_bMpeg,
m_has_audio, m_hdmi_clock_sync, m_thread_player))
goto do_exit;
if(m_has_video)
{
int width = 1280;
int height = 720;
if(m_hints_video.width <= 720)
{
width = 720; height = 576;
}
else if(m_hints_video.width <= 1280)
{
width = 1280; height = 720;
}
else
{
width = 1920; height = 1080;
}
memset(&tv_state, 0, sizeof(TV_GET_STATE_RESP_T));
m_BcmHost.vc_tv_get_state(&tv_state);
int32_t num_modes;
HDMI_RES_GROUP_T prefer_group;
int i = 0;
uint32_t prefer_mode;
#define TV_MAX_SUPPORTED_MODES 60
TV_SUPPORTED_MODE_T supported_modes[TV_MAX_SUPPORTED_MODES];
uint32_t group = HDMI_RES_GROUP_CEA;
int mode = 1;
if(m_filename.find("3DSBS") != string::npos)
m_3d = true;
if(m_3d)
{
group = HDMI_RES_GROUP_CEA_3D;
}
else
{
group = HDMI_RES_GROUP_CEA;
}
num_modes = m_BcmHost.vc_tv_hdmi_get_supported_modes((HDMI_RES_GROUP_T)group,
supported_modes,
TV_MAX_SUPPORTED_MODES,
&prefer_group,
&prefer_mode);
float last_diff = (float)m_player_video.GetFPS();
if(m_3d)
last_diff *= 2;
TV_SUPPORTED_MODE_T *tv_found = NULL;
if (num_modes > 0 && prefer_group != HDMI_RES_GROUP_INVALID)
{
TV_SUPPORTED_MODE_T *tv = supported_modes;
for (i=0; i<num_modes; i++, tv++)
{
float fps = ((group==HDMI_RES_GROUP_CEA_3D) ? (float)m_player_video.GetFPS() * 2.0f : (float)m_player_video.GetFPS());
if(tv->width == width && tv->height == height && fps <= (float)tv->frame_rate)
{
float diff = (float)tv->frame_rate - fps;
if(diff < 0.0f)
diff *= -1.0f;
if(diff < last_diff)
{
last_diff = diff;
tv_found = tv;
mode = supported_modes[i].code;
}
}
else if( fps <= (float)tv->frame_rate && tv->width >= width && tv->height >= height)
{
float diff = (float)tv->frame_rate - fps;
if(diff < 0.0f)
diff *= -1.0f;
if(diff < last_diff)
{
last_diff = diff;
tv_found = tv;
mode = supported_modes[i].code;
}
}
}
if(!tv_found)
{
tv = supported_modes;
for (i=0; i<num_modes; i++, tv++)
{
if(tv->width == width && tv->height == height)
{
tv_found = tv;
mode = supported_modes[i].code;
break;
}
}
}
if(tv_found)
printf("Output mode %d: %dx%d@%d %s%s:%x\n", i, tv_found->width, tv_found->height,
tv_found->frame_rate, tv_found->native?"N":"", tv_found->scan_mode?"I":"", tv_found->code);
}
if(tv_found)
m_BcmHost.vc_tv_hdmi_power_on_explicit(HDMI_MODE_HDMI, (HDMI_RES_GROUP_T)group, mode);
}
m_av_clock->OMXStateExecute();
m_av_clock->SetSpeed(DVD_PLAYSPEED_NORMAL);
if(m_has_subtitle && m_subtitle_index > (m_omx_reader.SubtitleStreamCount() - 1))
{
m_subtitle_index = m_omx_reader.SubtitleStreamCount() - 1;
m_omx_reader.SetActiveStream(OMXSTREAM_SUBTITLE, m_subtitle_index);
m_show_subtitle = true;
}
else
{
m_show_subtitle = false;
}
m_omx_reader.GetHints(OMXSTREAM_AUDIO, m_hints_audio);
if(m_has_audio && !m_player_audio.Open(m_hints_audio, m_av_clock, &m_omx_reader, deviceString,
m_passthrough, m_use_hw_audio, m_thread_player))
goto do_exit;
m_av_clock->OMXStateExecute();
m_av_clock->OMXReset();
m_av_clock->OMXResume();
struct timespec starttime, endtime;
while(!m_stop)
{
int ch[8];
int chnum = 0;
if(g_abort)
goto do_exit;
while((ch[chnum] = getchar()) != EOF) chnum++;
if (chnum > 1) ch[0] = ch[chnum - 1] | (ch[chnum - 2] << 8);
switch(ch[0])
{
case 'z':
m_tv_show_info = !m_tv_show_info;
vc_tv_show_info(m_tv_show_info);
break;
case '1':
SetSpeed(m_av_clock->OMXPlaySpeed() - 1);
break;
case '2':
SetSpeed(m_av_clock->OMXPlaySpeed() + 1);
break;
case 'j':
m_omx_reader.SetActiveStream(OMXSTREAM_AUDIO, m_omx_reader.GetAudioIndex() - 1);
break;
case 'k':
m_omx_reader.SetActiveStream(OMXSTREAM_AUDIO, m_omx_reader.GetAudioIndex() + 1);
break;
case 'i':
if(m_omx_reader.GetChapterCount() > 0)
{
m_omx_reader.SeekChapter(m_omx_reader.GetChapter() - 1, &startpts);
FlushStreams();
}
else
{
m_incr = -600.0;
}
break;
case 'o':
if(m_omx_reader.GetChapterCount() > 0)
{
m_omx_reader.SeekChapter(m_omx_reader.GetChapter() + 1, &startpts);
FlushStreams();
}
else
{
m_incr = 600.0;
}
break;
case 'n':
if(m_omx_reader.GetSubtitleIndex() > 0)
{
m_omx_reader.SetActiveStream(OMXSTREAM_SUBTITLE, m_omx_reader.GetSubtitleIndex() - 1);
m_player_video.FlushSubtitles();
}
break;
case 'm':
if(m_omx_reader.GetSubtitleIndex() > 0)
{
m_omx_reader.SetActiveStream(OMXSTREAM_SUBTITLE, m_omx_reader.GetSubtitleIndex() + 1);
m_player_video.FlushSubtitles();
}
break;
case 's':
m_show_subtitle = !m_show_subtitle;
break;
case 'q':
m_stop = true;
goto do_exit;
break;
case 0x5b44: // key left
m_incr = -30.0;
break;
case 0x5b43: // key right
m_incr = 30.0;
break;
case 0x5b41: // key up
m_incr = 600.0;
break;
case 0x5b42: // key down
m_incr = -600.0;
break;
case ' ':
case 'p':
m_Pause = !m_Pause;
if(m_Pause)
{
SetSpeed(OMX_PLAYSPEED_PAUSE);
m_av_clock->OMXPause();
}
else
{
SetSpeed(OMX_PLAYSPEED_NORMAL);
m_av_clock->OMXResume();
}
break;
default:
break;
}
if(m_Pause)
{
OMXClock::OMXSleep(2);
continue;
}
if(m_incr != 0 && !m_bMpeg)
{
int seek_flags = 0;
double seek_pos = 0;
double pts = 0;
pts = m_av_clock->GetPTS();
seek_pos = (pts / DVD_TIME_BASE) + m_incr;
seek_flags = m_incr < 0 ? AVSEEK_FLAG_BACKWARD : 0;
if(seek_pos < 0)
seek_pos = 0;
seek_pos *= 1000;
m_incr = 0;
if(m_omx_reader.SeekTime(seek_pos, seek_flags, &startpts))
FlushStreams();
}
/* when the audio buffer runs under 0.1 seconds we buffer up */
if(m_has_audio)
{
if(m_player_audio.GetDelay() < 0.1f && !m_buffer_empty)
{
if(!m_av_clock->OMXIsPaused())
{
m_av_clock->OMXPause();
//printf("buffering start\n");
m_buffer_empty = true;
clock_gettime(CLOCK_REALTIME, &starttime);
}
}
if(m_player_audio.GetDelay() > (AUDIO_BUFFER_SECONDS * 0.75f) && m_buffer_empty)
{
if(m_av_clock->OMXIsPaused())
{
m_av_clock->OMXResume();
//printf("buffering end\n");
m_buffer_empty = false;
}
}
if(m_buffer_empty)
{
clock_gettime(CLOCK_REALTIME, &endtime);
if((endtime.tv_sec - starttime.tv_sec) > 1)
{
m_buffer_empty = false;
m_av_clock->OMXResume();
//printf("buffering timed out\n");
}
}
}
if(!m_omx_pkt)
m_omx_pkt = m_omx_reader.Read();
if(m_omx_pkt && m_omx_reader.IsActive(OMXSTREAM_VIDEO, m_omx_pkt->stream_index))
{
if(m_omx_pkt->pts != DVD_NOPTS_VALUE)
m_omx_pkt->pts += (m_audio_offset_ms * 1000);
if(m_omx_pkt->dts != DVD_NOPTS_VALUE)
m_omx_pkt->dts += (m_audio_offset_ms * 1000);
if(m_player_video.AddPacket(m_omx_pkt))
m_omx_pkt = NULL;
else
OMXClock::OMXSleep(10);
if(m_tv_show_info)
{
char response[80];
vc_gencmd(response, sizeof response, "render_bar 4 video_fifo %d %d %d %d",
m_player_video.GetDecoderBufferSize()-m_player_video.GetDecoderFreeSpace(),
0 , 0, m_player_video.GetDecoderBufferSize());
vc_gencmd(response, sizeof response, "render_bar 5 audio_fifo %d %d %d %d",
(int)(100.0*m_player_audio.GetDelay()), 0, 0, 100*AUDIO_BUFFER_SECONDS);
}
}
else if(m_omx_pkt && m_omx_pkt->codec_type == AVMEDIA_TYPE_AUDIO)
{
if(m_player_audio.AddPacket(m_omx_pkt))
m_omx_pkt = NULL;
else
OMXClock::OMXSleep(10);
}
else if(m_omx_pkt && m_omx_reader.IsActive(OMXSTREAM_SUBTITLE, m_omx_pkt->stream_index))
{
if(m_omx_pkt->size && (m_omx_pkt->hints.codec == CODEC_ID_TEXT ||
m_omx_pkt->hints.codec == CODEC_ID_SSA))
{
if(m_player_video.AddPacket(m_omx_pkt))
m_omx_pkt = NULL;
else
OMXClock::OMXSleep(10);
}
else
{
m_omx_reader.FreePacket(m_omx_pkt);
m_omx_pkt = NULL;
}
}
else
{
if(m_omx_pkt)
{
m_omx_reader.FreePacket(m_omx_pkt);
m_omx_pkt = NULL;
}
}
/* player got in an error state */
if(m_player_audio.Error())
{
printf("audio player error. emergency exit!!!\n");
goto do_exit;
}
CStdString strSubTitle = m_player_video.GetText();
if(strSubTitle.length() && m_show_subtitle)
{
if(last_sub != strSubTitle)
{
last_sub = strSubTitle;
printf("Text : %s\n", strSubTitle.c_str());
}
}
if(m_stats)
{
printf("V : %8.02f %8d %8d A : %8.02f %8.02f Cv : %8d Ca : %8d \r",
m_player_video.GetCurrentPTS() / DVD_TIME_BASE, m_player_video.GetDecoderBufferSize(),
m_player_video.GetDecoderFreeSpace(), m_player_audio.GetCurrentPTS() / DVD_TIME_BASE,
m_player_audio.GetDelay(), m_player_video.GetCached(), m_player_audio.GetCached());
}
if(m_omx_reader.IsEof())
break;
}
do_exit:
printf("\n");
if(!m_stop)
{
if(m_has_audio)
m_player_audio.WaitCompletion();
else if(m_has_video)
m_player_video.WaitCompletion();
}
m_BcmHost.vc_tv_hdmi_power_on_best(tv_state.width, tv_state.height, tv_state.frame_rate, HDMI_NONINTERLACED,
(EDID_MODE_MATCH_FLAG_T)(HDMI_MODE_MATCH_FRAMERATE|HDMI_MODE_MATCH_RESOLUTION|HDMI_MODE_MATCH_SCANMODE));
m_av_clock->OMXStop();
m_av_clock->OMXStateIdle();
m_player_video.Close();
m_player_audio.Close();
if(m_omx_pkt)
{
m_omx_reader.FreePacket(m_omx_pkt);
m_omx_pkt = NULL;
}
m_omx_reader.Close();
vc_tv_show_info(0);
g_OMX.Deinitialize();
g_RBP.Deinitialize();
printf("have a nice day ;)\n");
return 1;
}

11
profiler.sh Normal file
View file

@ -0,0 +1,11 @@
#!/bin/sh
insmod /lib/modules/3.1.10+/kernel/arch/arm/oprofile/oprofile.ko timer=1
opcontrol --init
opcontrol --vmlinux=/boot/vmlinux
opcontrol --start
./omxplayer.bin -s -o hdmi /media/net/1080p/Gone\ in\ Sixty\ Seconds\ 2000.mkv
opcontrol --dump
opreport -l

295
system.h Normal file
View file

@ -0,0 +1,295 @@
#pragma once
/*
* Copyright (C) 2005-2008 Team XBMC
* http://www.xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with XBMC; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#if defined(HAVE_CONFIG_H) && !defined(TARGET_WINDOWS)
#include "config.h"
#endif
/*****************
* All platforms
*****************/
#define HAS_DVD_SWSCALE
#define HAS_DVDPLAYER
#define HAS_EVENT_SERVER
#define HAS_KARAOKE
#define HAS_SCREENSAVER
#define HAS_PYTHON
#define HAS_SYSINFO
#define HAS_UPNP
#define HAS_VIDEO_PLAYBACK
#define HAS_VISUALISATION
#ifdef HAVE_LIBMICROHTTPD
#define HAS_WEB_SERVER
#define HAS_WEB_INTERFACE
#endif
#define HAS_JSONRPC
#define HAS_HTTPAPI
#ifdef USE_ASAP_CODEC
#define HAS_ASAP_CODEC
#endif
#define HAS_FILESYSTEM
#define HAS_FILESYSTEM_CDDA
#define HAS_FILESYSTEM_RTV
#define HAS_FILESYSTEM_DAAP
#define HAS_FILESYSTEM_SAP
#define HAS_FILESYSTEM_VTP
#define HAS_FILESYSTEM_HTSP
#ifdef HAVE_LIBSMBCLIENT
#define HAS_FILESYSTEM_SMB
#endif
#ifdef HAVE_LIBNFS
#define HAS_FILESYSTEM_NFS
#endif
#ifdef HAVE_LIBAFPCLIENT
#define HAS_FILESYSTEM_AFP
#endif
#ifdef HAVE_LIBPLIST
#define HAS_AIRPLAY
#endif
#ifdef HAVE_LIBSHAIRPORT
#define HAS_AIRTUNES
#endif
/**********************
* Non-free Components
**********************/
#if defined(TARGET_WINDOWS)
#define HAS_FILESYSTEM_RAR
#else
#if defined(HAVE_XBMC_NONFREE)
#define HAS_FILESYSTEM_RAR
#endif
#endif
/*****************
* Win32 Specific
*****************/
#if defined(TARGET_WINDOWS)
#define HAS_SDL
#define HAS_SDL_JOYSTICK
#define HAS_DVD_DRIVE
#define HAS_WIN32_NETWORK
#define HAS_IRSERVERSUITE
#define HAS_AUDIO
#define HAVE_LIBCRYSTALHD 2
#define HAS_WEB_SERVER
#define HAS_WEB_INTERFACE
#define HAVE_LIBSSH
#define HAS_LIBRTMP
#define HAVE_LIBBLURAY
#define HAS_ASAP_CODEC
#define HAVE_YAJL_YAJL_VERSION_H
#define HAS_FILESYSTEM_SMB
#define HAS_FILESYSTEM_NFS
#endif
/*****************
* Mac Specific
*****************/
#if defined(TARGET_DARWIN)
#if defined(TARGET_DARWIN_OSX)
#define HAS_GL
#define HAS_SDL
#define HAS_SDL_AUDIO
#define HAS_SDL_OPENGL
#define HAS_SDL_WIN_EVENTS
#endif
#define HAS_ZEROCONF
#define HAS_LINUX_NETWORK
#endif
/*****************
* Linux Specific
*****************/
#if defined(TARGET_LINUX)
#if defined(HAVE_LIBAVAHI_COMMON) && defined(HAVE_LIBAVAHI_CLIENT)
#define HAS_ZEROCONF
#define HAS_AVAHI
#endif
#define HAS_LCD
#ifdef HAVE_DBUS
#define HAS_DBUS
#define HAS_DBUS_SERVER
#endif
#define HAS_GL
#ifdef HAVE_X11
#define HAS_GLX
#endif
#ifdef HAVE_SDL
#define HAS_SDL
#ifndef HAS_SDL_OPENGL
#define HAS_SDL_OPENGL
#define HAS_SDL_AUDIO
#define HAS_SDL_WIN_EVENTS
#endif
#else
#define HAS_LINUX_EVENTS
#endif
#define HAS_LINUX_NETWORK
#define HAS_LIRC
#ifdef HAVE_LIBPULSE
#define HAS_PULSEAUDIO
#endif
#ifdef HAVE_LIBXRANDR
#define HAS_XRANDR
#endif
#define HAS_AIRPLAY
#endif
#ifdef HAVE_LIBSSH
#define HAS_FILESYSTEM_SFTP
#endif
/*****************
* Git revision
*****************/
#if defined(TARGET_DARWIN)
#include "../git_revision.h"
#endif
#ifndef GIT_REV
#define GIT_REV "Unknown"
#endif
/****************************************
* Additional platform specific includes
****************************************/
#if defined(TARGET_WINDOWS)
#include <windows.h>
#define DIRECTINPUT_VERSION 0x0800
#include "mmsystem.h"
#include "DInput.h"
#include "DSound.h"
#define DSSPEAKER_USE_DEFAULT DSSPEAKER_STEREO
#define LPDIRECTSOUND8 LPDIRECTSOUND
#undef GetFreeSpace
#include "PlatformInclude.h"
#ifdef HAS_DX
#include "D3D9.h" // On Win32, we're always using DirectX for something, whether it be the actual rendering
#include "D3DX9.h" // or the reference video clock.
#else
#include <d3d9types.h>
#endif
#ifdef HAS_SDL
#include "SDL\SDL.h"
#endif
#endif
#if defined(TARGET_POSIX)
#include <time.h>
#include <sys/time.h>
#include <sys/types.h>
#include <errno.h>
#include "PlatformDefs.h"
#endif
// ARM does not support certain features... disable them here!
#ifdef _ARMEL
#undef HAS_AVAHI
#undef HAS_ZEROCONF
#undef HAS_VISUALISATION
#undef HAS_FILESYSTEM_HTSP
#endif
// EGL detected. Dont use GLX!
#ifdef HAVE_LIBEGL
#undef HAS_GLX
#define HAS_EGL
#endif
// GLES2.0 detected. Dont use GL!
#ifdef HAVE_LIBGLESV2
#undef HAS_GL
#define HAS_GLES 2
#endif
// GLES1.0 detected. Dont use GL!
#ifdef HAVE_LIBGLES
#undef HAS_GL
#define HAS_GLES 1
#endif
#ifdef HAS_GL
#if defined(TARGET_WINDOWS)
#include "GL/glew.h"
#include <GL/gl.h>
#include <GL/glu.h>
//#include <GL/wglext.h>
#elif defined(TARGET_DARWIN)
#include <GL/glew.h>
#include <OpenGL/gl.h>
#elif defined(TARGET_LINUX)
#include <GL/glew.h>
#include <GL/gl.h>
#endif
#endif
#if HAS_GLES == 2
#if defined(TARGET_DARWIN)
#include <OpenGLES/ES2/gl.h>
#include <OpenGLES/ES2/glext.h>
#else
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
#endif
#endif
#ifdef HAS_DVD_DRIVE
#define HAS_CDDA_RIPPER
#endif
#define SAFE_DELETE(p) do { delete (p); (p)=NULL; } while (0)
#define SAFE_DELETE_ARRAY(p) do { delete[] (p); (p)=NULL; } while (0)
#define SAFE_RELEASE(p) do { if(p) { (p)->Release(); (p)=NULL; } } while (0)
// Useful pixel colour manipulation macros
#define GET_A(color) ((color >> 24) & 0xFF)
#define GET_R(color) ((color >> 16) & 0xFF)
#define GET_G(color) ((color >> 8) & 0xFF)
#define GET_B(color) ((color >> 0) & 0xFF)

209
utils/MathUtils.h Normal file
View file

@ -0,0 +1,209 @@
#pragma once
/*
* Copyright (C) 2005-2008 Team XBMC
* http://www.xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with XBMC; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#include <stdint.h>
#include <cassert>
#include <climits>
#include <cmath>
#include <stdio.h>
/*! \brief Math utility class.
Note that the test() routine should return true for all implementations
See http://ldesoras.free.fr/doc/articles/rounding_en.pdf for an explanation
of the technique used on x86.
*/
namespace MathUtils
{
// GCC does something stupid with optimization on release builds if we try
// to assert in these functions
/*! \brief Round to nearest integer.
This routine does fast rounding to the nearest integer.
In the case (k + 0.5 for any integer k) we round up to k+1, and in all other
instances we should return the nearest integer.
Thus, { -1.5, -0.5, 0.5, 1.5 } is rounded to { -1, 0, 1, 2 }.
It preserves the property that round(k) - round(k-1) = 1 for all doubles k.
Make sure MathUtils::test() returns true for each implementation.
\sa truncate_int, test
*/
inline int round_int (double x)
{
assert(x > static_cast<double>(INT_MIN / 2) - 1.0);
assert(x < static_cast <double>(INT_MAX / 2) + 1.0);
const float round_to_nearest = 0.5f;
int i;
#ifndef _LINUX
__asm
{
fld x
fadd st, st (0)
fadd round_to_nearest
fistp i
sar i, 1
}
#else
#if defined(__powerpc__) || defined(__ppc__)
i = floor(x + round_to_nearest);
#elif defined(__arm__)
// From 'ARM®v7-M Architecture Reference Manual' page A7-569:
// "The floating-point to integer operation (vcvt) [normally] uses the Round towards Zero rounding mode"
// Because of this...we must use some less-than-straightforward logic to perform this operation without
// changing the rounding mode flags
/* The assembly below implements the following logic:
if (x < 0)
inc = -0.5f
else
inc = 0.5f
int_val = trunc(x+inc);
err = x - int_val;
if (err == 0.5f)
int_val++;
return int_val;
*/
/*
__asm__ __volatile__ (
"vmov.F64 d1,%[rnd_val] \n\t" // Copy round_to_nearest into a working register (d1 = 0.5)
"fcmpezd %P[value] \n\t" // Check value against zero (value == 0?)
"fmstat \n\t" // Copy the floating-point status flags into the general-purpose status flags
"it mi \n\t"
"vnegmi.F64 d1, d1 \n\t" // if N-flag is set, negate round_to_nearest (if (value < 0) d1 = -1 * d1)
"vadd.F64 d1,%P[value],d1 \n\t" // Add round_to_nearest to value, store result in working register (d1 += value)
"vcvt.S32.F64 s3,d1 \n\t" // Truncate(round towards zero) (s3 = (int)d1)
"vmov %[result],s3 \n\t" // Store the integer result in a general-purpose register (result = s3)
"vcvt.F64.S32 d1,s3 \n\t" // Convert back to floating-point (d1 = (double)s3)
"vsub.F64 d1,%P[value],d1 \n\t" // Calculate the error (d1 = value - d1)
"vmov.F64 d2,%[rnd_val] \n\t" // d2 = 0.5;
"fcmped d1, d2 \n\t" // (d1 == 0.5?)
"fmstat \n\t" // Copy the floating-point status flags into the general-purpose status flags
"it eq \n\t"
"addeq %[result],#1 \n\t" // (if (d1 == d2) result++;)
: [result] "=r"(i) // Outputs
: [rnd_val] "Dv" (round_to_nearest), [value] "w"(x) // Inputs
: "d1", "d2", "s3" // Clobbers
);
*/
i = floor(x + round_to_nearest);
#else
__asm__ __volatile__ (
"fadd %%st\n\t"
"fadd %%st(1)\n\t"
"fistpl %0\n\t"
"sarl $1, %0\n"
: "=m"(i) : "u"(round_to_nearest), "t"(x) : "st"
);
#endif
#endif
return (i);
}
/*! \brief Truncate to nearest integer.
This routine does fast truncation to an integer.
It should simply drop the fractional portion of the floating point number.
Make sure MathUtils::test() returns true for each implementation.
\sa round_int, test
*/
inline int truncate_int(double x)
{
assert(x > static_cast<double>(INT_MIN / 2) - 1.0);
assert(x < static_cast <double>(INT_MAX / 2) + 1.0);
#if !defined(__powerpc__) && !defined(__ppc__) && !defined(__arm__)
const float round_towards_m_i = -0.5f;
#endif
int i;
#ifndef _LINUX
__asm
{
fld x
fadd st, st (0)
fabs
fadd round_towards_m_i
fistp i
sar i, 1
}
#else
#if defined(__powerpc__) || defined(__ppc__)
return (int)x;
#elif defined(__arm__)
/*
__asm__ __volatile__ (
"vcvt.S32.F64 %[result],%P[value] \n\t" // Truncate(round towards zero) and store the result
: [result] "=w"(i) // Outputs
: [value] "w"(x) // Inputs
);
return i;
*/
return (int)x;
#else
__asm__ __volatile__ (
"fadd %%st\n\t"
"fabs\n\t"
"fadd %%st(1)\n\t"
"fistpl %0\n\t"
"sarl $1, %0\n"
: "=m"(i) : "u"(round_towards_m_i), "t"(x) : "st"
);
#endif
#endif
if (x < 0)
i = -i;
return (i);
}
inline int64_t abs(int64_t a)
{
return (a < 0) ? -a : a;
}
inline void hack()
{
// stupid hack to keep compiler from dropping these
// functions as unused
MathUtils::round_int(0.0);
MathUtils::truncate_int(0.0);
MathUtils::abs(0);
}
#if 0
/*! \brief test routine for round_int and truncate_int
Must return true on all platforms.
*/
inline bool test()
{
for (int i = -8; i < 8; ++i)
{
double d = 0.25*i;
int r = (i < 0) ? (i - 1) / 4 : (i + 2) / 4;
int t = i / 4;
if (round_int(d) != r || truncate_int(d) != t)
return false;
}
return true;
}
#endif
} // namespace MathUtils

795
utils/PCMRemap.cpp Normal file
View file

@ -0,0 +1,795 @@
/*
* Copyright (C) 2005-2010 Team XBMC
* http://www.xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with XBMC; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#ifndef __STDC_LIMIT_MACROS
#define __STDC_LIMIT_MACROS
#endif
#include <cstdlib>
#include <string.h>
#include <stdio.h>
#include <math.h>
#include "MathUtils.h"
#include "PCMRemap.h"
#include "utils/log.h"
#ifdef _WIN32
#include "../win32/PlatformDefs.h"
#endif
static enum PCMChannels PCMLayoutMap[PCM_MAX_LAYOUT][PCM_MAX_CH + 1] =
{
/* 2.0 */ {PCM_FRONT_LEFT, PCM_FRONT_RIGHT, PCM_INVALID},
/* 2.1 */ {PCM_FRONT_LEFT, PCM_FRONT_RIGHT, PCM_LOW_FREQUENCY, PCM_INVALID},
/* 3.0 */ {PCM_FRONT_LEFT, PCM_FRONT_RIGHT, PCM_FRONT_CENTER, PCM_INVALID},
/* 3.1 */ {PCM_FRONT_LEFT, PCM_FRONT_RIGHT, PCM_FRONT_CENTER, PCM_LOW_FREQUENCY, PCM_INVALID},
/* 4.0 */ {PCM_FRONT_LEFT, PCM_FRONT_RIGHT, PCM_BACK_LEFT, PCM_BACK_RIGHT, PCM_INVALID},
/* 4.1 */ {PCM_FRONT_LEFT, PCM_FRONT_RIGHT, PCM_BACK_LEFT, PCM_BACK_RIGHT, PCM_LOW_FREQUENCY, PCM_INVALID},
/* 5.0 */ {PCM_FRONT_LEFT, PCM_FRONT_RIGHT, PCM_FRONT_CENTER, PCM_BACK_LEFT, PCM_BACK_RIGHT, PCM_INVALID},
/* 5.1 */ {PCM_FRONT_LEFT, PCM_FRONT_RIGHT, PCM_FRONT_CENTER, PCM_BACK_LEFT, PCM_BACK_RIGHT, PCM_LOW_FREQUENCY, PCM_INVALID},
/* 7.0 */ {PCM_FRONT_LEFT, PCM_FRONT_RIGHT, PCM_FRONT_CENTER, PCM_SIDE_LEFT, PCM_SIDE_RIGHT, PCM_BACK_LEFT, PCM_BACK_RIGHT, PCM_INVALID},
/* 7.1 */ {PCM_FRONT_LEFT, PCM_FRONT_RIGHT, PCM_FRONT_CENTER, PCM_SIDE_LEFT, PCM_SIDE_RIGHT, PCM_BACK_LEFT, PCM_BACK_RIGHT, PCM_LOW_FREQUENCY, PCM_INVALID}
};
/*
map missing output into channel @ volume level
the order of this table is important, mix tables can not depend on channels that have not been defined yet
eg, FC can only be mixed into FL, FR as they are the only channels that have been defined
*/
#define PCM_MAX_MIX 3
static struct PCMMapInfo PCMDownmixTable[PCM_MAX_CH][PCM_MAX_MIX] =
{
/* PCM_FRONT_LEFT */
{
{PCM_INVALID}
},
/* PCM_FRONT_RIGHT */
{
{PCM_INVALID}
},
/* PCM_FRONT_CENTER */
{
{PCM_FRONT_LEFT_OF_CENTER , 1.0},
{PCM_FRONT_RIGHT_OF_CENTER, 1.0},
{PCM_INVALID}
},
/* PCM_LOW_FREQUENCY */
{
/*
A/52B 7.8 paragraph 2 recomends +10db
but due to horrible clipping when normalize
is disabled we set this to 1.0
*/
{PCM_FRONT_LEFT , 1.0},//3.5},
{PCM_FRONT_RIGHT , 1.0},//3.5},
{PCM_INVALID}
},
/* PCM_BACK_LEFT */
{
{PCM_FRONT_LEFT , 1.0},
{PCM_INVALID}
},
/* PCM_BACK_RIGHT */
{
{PCM_FRONT_RIGHT , 1.0},
{PCM_INVALID}
},
/* PCM_FRONT_LEFT_OF_CENTER */
{
{PCM_FRONT_LEFT , 1.0},
{PCM_FRONT_CENTER , 1.0, true},
{PCM_INVALID}
},
/* PCM_FRONT_RIGHT_OF_CENTER */
{
{PCM_FRONT_RIGHT , 1.0},
{PCM_FRONT_CENTER , 1.0, true},
{PCM_INVALID}
},
/* PCM_BACK_CENTER */
{
{PCM_BACK_LEFT , 1.0},
{PCM_BACK_RIGHT , 1.0},
{PCM_INVALID}
},
/* PCM_SIDE_LEFT */
{
{PCM_FRONT_LEFT , 1.0},
{PCM_BACK_LEFT , 1.0},
{PCM_INVALID}
},
/* PCM_SIDE_RIGHT */
{
{PCM_FRONT_RIGHT , 1.0},
{PCM_BACK_RIGHT , 1.0},
{PCM_INVALID}
},
/* PCM_TOP_FRONT_LEFT */
{
{PCM_FRONT_LEFT , 1.0},
{PCM_INVALID}
},
/* PCM_TOP_FRONT_RIGHT */
{
{PCM_FRONT_RIGHT , 1.0},
{PCM_INVALID}
},
/* PCM_TOP_FRONT_CENTER */
{
{PCM_TOP_FRONT_LEFT , 1.0},
{PCM_TOP_FRONT_RIGHT , 1.0},
{PCM_INVALID}
},
/* PCM_TOP_CENTER */
{
{PCM_TOP_FRONT_LEFT , 1.0},
{PCM_TOP_FRONT_RIGHT , 1.0},
{PCM_INVALID}
},
/* PCM_TOP_BACK_LEFT */
{
{PCM_BACK_LEFT , 1.0},
{PCM_INVALID}
},
/* PCM_TOP_BACK_RIGHT */
{
{PCM_BACK_RIGHT , 1.0},
{PCM_INVALID}
},
/* PCM_TOP_BACK_CENTER */
{
{PCM_TOP_BACK_LEFT , 1.0},
{PCM_TOP_BACK_RIGHT , 1.0},
{PCM_INVALID}
}
};
CPCMRemap::CPCMRemap() :
m_inSet (false),
m_outSet (false),
m_inChannels (0),
m_outChannels (0),
m_inSampleSize(0),
m_ignoreLayout(false),
m_buf(NULL),
m_bufsize(0),
m_attenuation (1.0),
m_attenuationInc(0.0),
m_attenuationMin(1.0),
m_sampleRate (48000.0), //safe default
m_holdCounter (0),
m_limiterEnabled(false)
{
Dispose();
}
CPCMRemap::~CPCMRemap()
{
Dispose();
}
void CPCMRemap::Dispose()
{
free(m_buf);
m_buf = NULL;
m_bufsize = 0;
}
/* resolves the channels recursively and returns the new index of tablePtr */
struct PCMMapInfo* CPCMRemap::ResolveChannel(enum PCMChannels channel, float level, bool ifExists, std::vector<enum PCMChannels> path, struct PCMMapInfo *tablePtr)
{
if (channel == PCM_INVALID) return tablePtr;
/* if its a 1 to 1 mapping, return */
if (m_useable[channel])
{
tablePtr->channel = channel;
tablePtr->level = level;
++tablePtr;
tablePtr->channel = PCM_INVALID;
return tablePtr;
} else
if (ifExists)
level /= 2;
struct PCMMapInfo *info;
std::vector<enum PCMChannels>::iterator itt;
for(info = PCMDownmixTable[channel]; info->channel != PCM_INVALID; ++info)
{
/* make sure we are not about to recurse into ourself */
bool found = false;
for(itt = path.begin(); itt != path.end(); ++itt)
if (*itt == info->channel)
{
found = true;
break;
}
if (found)
continue;
path.push_back(channel);
float l = (info->level * (level / 100)) * 100;
tablePtr = ResolveChannel(info->channel, l, info->ifExists, path, tablePtr);
path.pop_back();
}
return tablePtr;
}
/*
Builds a lookup table without extra adjustments, useful if we simply
want to find out which channels are active.
For final adjustments, BuildMap() is used.
*/
void CPCMRemap::ResolveChannels()
{
unsigned int in_ch, out_ch;
bool hasSide = false;
bool hasBack = false;
memset(m_useable, 0, sizeof(m_useable));
if (!m_outSet)
{
/* Output format is not known yet, assume the full configured map.
* Note that m_ignoreLayout-using callers normally ignore the result of
* this function when !m_outSet, when it is called only for an advice for
* the caller of SetInputFormat about the best possible output map, and
* they can still set their output format arbitrarily in their call to
* SetOutputFormat. */
for (enum PCMChannels *chan = PCMLayoutMap[m_channelLayout]; *chan != PCM_INVALID; ++chan)
m_useable[*chan] = true;
}
else if (m_ignoreLayout)
{
for(out_ch = 0; out_ch < m_outChannels; ++out_ch)
m_useable[m_outMap[out_ch]] = true;
}
else
{
/* figure out what channels we have and can use */
for(enum PCMChannels *chan = PCMLayoutMap[m_channelLayout]; *chan != PCM_INVALID; ++chan)
{
for(out_ch = 0; out_ch < m_outChannels; ++out_ch)
if (m_outMap[out_ch] == *chan)
{
m_useable[*chan] = true;
break;
}
}
}
/* force mono audio to front left and front right */
if (!m_ignoreLayout && m_inChannels == 1 && m_inMap[0] == PCM_FRONT_CENTER
&& m_useable[PCM_FRONT_LEFT] && m_useable[PCM_FRONT_RIGHT])
{
CLog::Log(LOGDEBUG, "CPCMRemap: Mapping mono audio to front left and front right");
m_useable[PCM_FRONT_CENTER] = false;
m_useable[PCM_FRONT_LEFT_OF_CENTER] = false;
m_useable[PCM_FRONT_RIGHT_OF_CENTER] = false;
}
/* see if our input has side/back channels */
for(in_ch = 0; in_ch < m_inChannels; ++in_ch)
switch(m_inMap[in_ch])
{
case PCM_SIDE_LEFT:
case PCM_SIDE_RIGHT:
hasSide = true;
break;
case PCM_BACK_LEFT:
case PCM_BACK_RIGHT:
hasBack = true;
break;
default:;
}
/* if our input has side, and not back channels, and our output doesnt have side channels */
if (hasSide && !hasBack && (!m_useable[PCM_SIDE_LEFT] || !m_useable[PCM_SIDE_RIGHT]))
{
CLog::Log(LOGDEBUG, "CPCMRemap: Forcing side channel map to back channels");
for(in_ch = 0; in_ch < m_inChannels; ++in_ch)
if (m_inMap[in_ch] == PCM_SIDE_LEFT ) m_inMap[in_ch] = PCM_BACK_LEFT;
else if (m_inMap[in_ch] == PCM_SIDE_RIGHT) m_inMap[in_ch] = PCM_BACK_RIGHT;
}
/* resolve all the channels */
struct PCMMapInfo table[PCM_MAX_CH + 1], *info, *dst;
std::vector<enum PCMChannels> path;
for (int i = 0; i < PCM_MAX_CH + 1; i++)
{
for (int j = 0; j < PCM_MAX_CH + 1; j++)
m_lookupMap[i][j].channel = PCM_INVALID;
}
memset(m_counts, 0, sizeof(m_counts));
for(in_ch = 0; in_ch < m_inChannels; ++in_ch) {
for (int i = 0; i < PCM_MAX_CH + 1; i++)
table[i].channel = PCM_INVALID;
ResolveChannel(m_inMap[in_ch], 1.0f, false, path, table);
for(info = table; info->channel != PCM_INVALID; ++info)
{
/* find the end of the table */
for(dst = m_lookupMap[info->channel]; dst->channel != PCM_INVALID; ++dst);
/* append it to the table and set its input offset */
dst->channel = m_inMap[in_ch];
dst->in_offset = in_ch * 2;
dst->level = info->level;
m_counts[dst->channel]++;
}
}
}
/*
builds a lookup table to convert from the input mapping to the output
mapping, this decreases the amount of work per sample to remap it.
*/
void CPCMRemap::BuildMap()
{
struct PCMMapInfo *dst;
unsigned int out_ch;
if (!m_inSet || !m_outSet) return;
m_inStride = m_inSampleSize * m_inChannels ;
m_outStride = m_inSampleSize * m_outChannels;
/* see if we need to normalize the levels */
bool dontnormalize = 1;
CLog::Log(LOGDEBUG, "CPCMRemap: Downmix normalization is %s", (dontnormalize ? "disabled" : "enabled"));
ResolveChannels();
/* convert the levels into RMS values */
float loudest = 0.0;
bool hasLoudest = false;
for(out_ch = 0; out_ch < m_outChannels; ++out_ch)
{
float scale = 0;
int count = 0;
for(dst = m_lookupMap[m_outMap[out_ch]]; dst->channel != PCM_INVALID; ++dst)
{
dst->copy = false;
dst->level = dst->level / sqrt((float)m_counts[dst->channel]);
scale += dst->level;
++count;
}
/* if there is only 1 channel to mix, and the level is 1.0, then just copy the channel */
dst = m_lookupMap[m_outMap[out_ch]];
if (count == 1 && dst->level > 0.99 && dst->level < 1.01)
dst->copy = true;
/* normalize the levels if it is turned on */
if (!dontnormalize)
for(dst = m_lookupMap[m_outMap[out_ch]]; dst->channel != PCM_INVALID; ++dst)
{
dst->level /= scale;
/* find the loudest output level we have that is not 1-1 */
if (dst->level < 1.0 && loudest < dst->level)
{
loudest = dst->level;
hasLoudest = true;
}
}
}
/* adjust the channels that are too loud */
for(out_ch = 0; out_ch < m_outChannels; ++out_ch)
{
CStdString s = "", f;
for(dst = m_lookupMap[m_outMap[out_ch]]; dst->channel != PCM_INVALID; ++dst)
{
if (hasLoudest && dst->copy)
{
dst->level = loudest;
dst->copy = false;
}
f.Format("%s(%f%s) ", PCMChannelStr(dst->channel).c_str(), dst->level, dst->copy ? "*" : "");
s += f;
}
CLog::Log(LOGDEBUG, "CPCMRemap: %s = %s\n", PCMChannelStr(m_outMap[out_ch]).c_str(), s.c_str());
}
}
void CPCMRemap::DumpMap(CStdString info, unsigned int channels, enum PCMChannels *channelMap)
{
if (channelMap == NULL)
{
CLog::Log(LOGINFO, "CPCMRemap: %s channel map: NULL", info.c_str());
return;
}
CStdString mapping;
for(unsigned int i = 0; i < channels; ++i)
mapping += ((i == 0) ? "" : ",") + PCMChannelStr(channelMap[i]);
CLog::Log(LOGINFO, "CPCMRemap: %s channel map: %s\n", info.c_str(), mapping.c_str());
}
void CPCMRemap::Reset()
{
m_inSet = false;
m_outSet = false;
Dispose();
}
/* sets the input format, and returns the requested channel layout */
enum PCMChannels *CPCMRemap::SetInputFormat(unsigned int channels, enum PCMChannels *channelMap, unsigned int sampleSize, unsigned int sampleRate)
{
m_inChannels = channels;
m_inSampleSize = sampleSize;
m_sampleRate = sampleRate;
m_inSet = channelMap != NULL;
if (channelMap)
memcpy(m_inMap, channelMap, sizeof(enum PCMChannels) * channels);
/* fix me later */
assert(sampleSize == 2);
/* get the audio layout, and count the channels in it */
m_channelLayout = PCM_LAYOUT_2_0;
if (m_channelLayout >= PCM_MAX_LAYOUT) m_channelLayout = PCM_LAYOUT_2_0;
DumpMap("I", channels, channelMap);
BuildMap();
/* now remove the empty channels from PCMLayoutMap;
* we don't perform upmixing so we want the minimum amount of those */
if (channelMap) {
if (!m_outSet)
ResolveChannels(); /* Do basic channel resolving to find out the empty channels;
* If m_outSet == true, this was done already by BuildMap() above */
int i = 0;
for (enum PCMChannels *chan = PCMLayoutMap[m_channelLayout]; *chan != PCM_INVALID; ++chan)
if (m_lookupMap[*chan][0].channel != PCM_INVALID) {
/* something is mapped here, so add the channel */
m_layoutMap[i++] = *chan;
}
m_layoutMap[i] = PCM_INVALID;
} else
memcpy(m_layoutMap, PCMLayoutMap[m_channelLayout], sizeof(PCMLayoutMap[m_channelLayout]));
m_attenuation = 1.0;
m_attenuationInc = 1.0;
m_holdCounter = 0;
return m_layoutMap;
}
/* sets the output format supported by the audio renderer */
void CPCMRemap::SetOutputFormat(unsigned int channels, enum PCMChannels *channelMap, bool ignoreLayout/* = false */)
{
m_outChannels = channels;
m_outSet = channelMap != NULL;
m_ignoreLayout = ignoreLayout;
if (channelMap)
memcpy(m_outMap, channelMap, sizeof(enum PCMChannels) * channels);
DumpMap("O", channels, channelMap);
BuildMap();
m_attenuation = 1.0;
m_attenuationInc = 1.0;
m_holdCounter = 0;
}
void CPCMRemap::Remap(void *data, void *out, unsigned int samples, long drc)
{
float gain = 1.0f;
if (drc > 0)
gain = pow(10.0f, (float)drc / 1000.0f);
Remap(data, out, samples, gain);
}
/* remap the supplied data into out, which must be pre-allocated */
void CPCMRemap::Remap(void *data, void *out, unsigned int samples, float gain /*= 1.0f*/)
{
CheckBufferSize(samples * m_outChannels * sizeof(float));
//set output buffer to 0
memset(out, 0, samples * m_outChannels * m_inSampleSize);
//set intermediate buffer to 0
memset(m_buf, 0, m_bufsize);
ProcessInput(data, out, samples, gain);
//AddGain(m_buf, samples * m_outChannels, gain);
//ProcessLimiter(samples, gain);
ProcessOutput(out, samples, gain);
}
void CPCMRemap::CheckBufferSize(int size)
{
if (m_bufsize < size)
{
m_bufsize = size;
m_buf = (float*)realloc(m_buf, m_bufsize);
}
}
void CPCMRemap::ProcessInput(void* data, void* out, unsigned int samples, float gain)
{
for (unsigned int ch = 0; ch < m_outChannels; ch++)
{
struct PCMMapInfo *info = m_lookupMap[m_outMap[ch]];
if (info->channel == PCM_INVALID)
continue;
if (info->copy && gain == 1.0f) //do direct copy
{
uint8_t* src = (uint8_t*)data + info->in_offset;
uint8_t* dst = (uint8_t*)out + ch * m_inSampleSize;
uint8_t* dstend = dst + samples * m_outStride;
while (dst < dstend)
{
*(int16_t*)dst = *(int16_t*)src;
src += m_inStride;
dst += m_outStride;
}
}
else //needs some volume change or mixing, put into intermediate buffer
{
for(; info->channel != PCM_INVALID; info++)
{
uint8_t* src = (uint8_t*)data + info->in_offset;
float* dst = m_buf + ch;
float* dstend = dst + samples * m_outChannels;
while (dst < dstend)
{
*dst += (float)(*(int16_t*)src) * info->level;
src += m_inStride;
dst += m_outChannels;
}
}
}
}
}
void CPCMRemap::AddGain(float* buf, unsigned int samples, float gain)
{
if (gain != 1.0f) //needs a gain change
{
float* ptr = m_buf;
float* end = m_buf + samples;
while (ptr < end)
*(ptr++) *= gain;
}
}
void CPCMRemap::ProcessLimiter(unsigned int samples, float gain)
{
//check total gain for each output channel
float highestgain = 1.0f;
for (unsigned int ch = 0; ch < m_outChannels; ch++)
{
struct PCMMapInfo *info = m_lookupMap[m_outMap[ch]];
if (info->channel == PCM_INVALID)
continue;
float chgain = 0.0f;
for(; info->channel != PCM_INVALID; info++)
chgain += info->level * gain;
if (chgain > highestgain)
highestgain = chgain;
}
m_attenuationMin = 1.0f;
//if one of the channels can clip, enable a limiter
if (highestgain > 1.0001f)
{
m_attenuationMin = m_attenuation;
if (!m_limiterEnabled)
{
CLog::Log(LOGDEBUG, "CPCMRemap:: max gain: %f, enabling limiter", highestgain);
m_limiterEnabled = true;
}
for (unsigned int i = 0; i < samples; i++)
{
//for each collection of samples, get the highest absolute value
float maxAbs = 0.0f;
for (unsigned int outch = 0; outch < m_outChannels; outch++)
{
float absval = fabs(m_buf[i * m_outChannels + outch]) / 32768.0f;
if (maxAbs < absval)
maxAbs = absval;
}
//if attenuatedAbs is higher than 1.0f, audio is clipping
float attenuatedAbs = maxAbs * m_attenuation;
if (attenuatedAbs > 1.0f)
{
//set m_attenuation so that m_attenuation * sample is the maximum output value
m_attenuation = 1.0f / maxAbs;
if (m_attenuation < m_attenuationMin)
m_attenuationMin = m_attenuation;
//value to add to m_attenuation to make it 1.0f
m_attenuationInc = 1.0f - m_attenuation;
//amount of samples to hold m_attenuation
m_holdCounter = MathUtils::round_int(m_sampleRate * 0.025f);
}
else if (m_attenuation < 1.0f && attenuatedAbs > 0.95f)
{
//if we're attenuating and we get within 5% of clipping, hold m_attenuation
m_attenuationInc = 1.0f - m_attenuation;
m_holdCounter = MathUtils::round_int(m_sampleRate * 0.025f);
}
//apply attenuation
for (unsigned int outch = 0; outch < m_outChannels; outch++)
m_buf[i * m_outChannels + outch] *= m_attenuation;
if (m_holdCounter)
{
//hold m_attenuation
m_holdCounter--;
}
else if (m_attenuationInc > 0.0f)
{
//move m_attenuation to 1.0 in g_advancedSettings.m_limiterRelease seconds
m_attenuation += m_attenuationInc / m_sampleRate / 0.1f;
if (m_attenuation > 1.0f)
{
m_attenuation = 1.0f;
m_attenuationInc = 0.0f;
}
}
}
}
else
{
if (m_limiterEnabled)
{
CLog::Log(LOGDEBUG, "CPCMRemap:: max gain: %f, disabling limiter", highestgain);
m_limiterEnabled = false;
}
//reset the limiter
m_attenuation = 1.0f;
m_attenuationInc = 0.0f;
m_holdCounter = 0;
}
}
void CPCMRemap::ProcessOutput(void* out, unsigned int samples, float gain)
{
//copy from intermediate buffer to output
for (unsigned int ch = 0; ch < m_outChannels; ch++)
{
struct PCMMapInfo *info = m_lookupMap[m_outMap[ch]];
if (info->channel == PCM_INVALID)
continue;
if (!info->copy || gain != 1.0f)
{
float* src = m_buf + ch;
uint8_t* dst = (uint8_t*)out + ch * m_inSampleSize;
uint8_t* dstend = dst + samples * m_outStride;
while(dst < dstend)
{
*(int16_t*)dst = MathUtils::round_int(std::min(std::max(*src, (float)INT16_MIN), (float)INT16_MAX));
src += m_outChannels;
dst += m_outStride;
}
}
}
}
bool CPCMRemap::CanRemap()
{
return (m_inSet && m_outSet);
}
int CPCMRemap::InBytesToFrames(int bytes)
{
return bytes / m_inSampleSize / m_inChannels;
}
int CPCMRemap::FramesToOutBytes(int frames)
{
return frames * m_inSampleSize * m_outChannels;
}
int CPCMRemap::FramesToInBytes(int frames)
{
return frames * m_inSampleSize * m_inChannels;
}
CStdString CPCMRemap::PCMChannelStr(enum PCMChannels ename)
{
const char* PCMChannelName[] =
{
"FL",
"FR",
"CE",
"LFE",
"BL",
"BR",
"FLOC",
"FROC",
"BC",
"SL",
"SR",
"TFL",
"TFR",
"TFC",
"TC",
"TBL",
"TBR",
"TBC"
};
int namepos = (int)ename;
CStdString namestr;
if (namepos < 0 || namepos >= (int)(sizeof(PCMChannelName) / sizeof(const char*)))
namestr.Format("UNKNOWN CHANNEL:%i", namepos);
else
namestr = PCMChannelName[namepos];
return namestr;
}
CStdString CPCMRemap::PCMLayoutStr(enum PCMLayout ename)
{
const char* PCMLayoutName[] =
{
"2.0",
"2.1",
"3.0",
"3.1",
"4.0",
"4.1",
"5.0",
"5.1",
"7.0",
"7.1"
};
int namepos = (int)ename;
CStdString namestr;
if (namepos < 0 || namepos >= (int)(sizeof(PCMLayoutName) / sizeof(const char*)))
namestr.Format("UNKNOWN LAYOUT:%i", namepos);
else
namestr = PCMLayoutName[namepos];
return namestr;
}

147
utils/PCMRemap.h Normal file
View file

@ -0,0 +1,147 @@
#ifndef __PCM_REMAP__H__
#define __PCM_REMAP__H__
/*
* Copyright (C) 2005-2010 Team XBMC
* http://www.xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with XBMC; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#include <stdint.h>
#include <vector>
#include "StdString.h"
#define PCM_MAX_CH 18
enum PCMChannels
{
PCM_INVALID = -1,
PCM_FRONT_LEFT,
PCM_FRONT_RIGHT,
PCM_FRONT_CENTER,
PCM_LOW_FREQUENCY,
PCM_BACK_LEFT,
PCM_BACK_RIGHT,
PCM_FRONT_LEFT_OF_CENTER,
PCM_FRONT_RIGHT_OF_CENTER,
PCM_BACK_CENTER,
PCM_SIDE_LEFT,
PCM_SIDE_RIGHT,
PCM_TOP_FRONT_LEFT,
PCM_TOP_FRONT_RIGHT,
PCM_TOP_FRONT_CENTER,
PCM_TOP_CENTER,
PCM_TOP_BACK_LEFT,
PCM_TOP_BACK_RIGHT,
PCM_TOP_BACK_CENTER
};
#define PCM_MAX_LAYOUT 10
enum PCMLayout
{
PCM_LAYOUT_2_0 = 0,
PCM_LAYOUT_2_1,
PCM_LAYOUT_3_0,
PCM_LAYOUT_3_1,
PCM_LAYOUT_4_0,
PCM_LAYOUT_4_1,
PCM_LAYOUT_5_0,
PCM_LAYOUT_5_1,
PCM_LAYOUT_7_0,
PCM_LAYOUT_7_1
};
struct PCMMapInfo
{
enum PCMChannels channel;
float level;
bool ifExists;
int in_offset;
bool copy;
};
//! Channels remapper class
/*!
The usual set-up process:
- user calls SetInputFormat with the input channels information
- SetInputFormat responds with a channelmap corresponding to the speaker
layout that the user has configured, with empty (according to information
calculated from the input channelmap) channels removed
- user uses this information to create the desired output channelmap,
and calls SetOutputFormat to set it (if the channelmap contains channels
that do not exist in the configured speaker layout, they will contain
only silence unless ignoreLayout is true)
*/
class CPCMRemap
{
protected:
bool m_inSet, m_outSet;
enum PCMLayout m_channelLayout;
unsigned int m_inChannels, m_outChannels;
unsigned int m_inSampleSize;
enum PCMChannels m_inMap [PCM_MAX_CH];
enum PCMChannels m_outMap[PCM_MAX_CH];
enum PCMChannels m_layoutMap[PCM_MAX_CH + 1];
bool m_ignoreLayout;
bool m_useable [PCM_MAX_CH];
int m_inStride, m_outStride;
struct PCMMapInfo m_lookupMap[PCM_MAX_CH + 1][PCM_MAX_CH + 1];
int m_counts[PCM_MAX_CH];
float* m_buf;
int m_bufsize;
float m_attenuation;
float m_attenuationInc;
float m_attenuationMin; //lowest attenuation value during a call of Remap(), used for the codec info
float m_sampleRate;
unsigned int m_holdCounter;
bool m_limiterEnabled;
struct PCMMapInfo* ResolveChannel(enum PCMChannels channel, float level, bool ifExists, std::vector<enum PCMChannels> path, struct PCMMapInfo *tablePtr);
void ResolveChannels(); //!< Partial BuildMap(), just enough to see which output channels are active
void BuildMap();
void DumpMap(CStdString info, int unsigned channels, enum PCMChannels *channelMap);
void Dispose();
CStdString PCMChannelStr(enum PCMChannels ename);
CStdString PCMLayoutStr(enum PCMLayout ename);
void CheckBufferSize(int size);
void ProcessInput(void* data, void* out, unsigned int samples, float gain);
void AddGain(float* buf, unsigned int samples, float gain);
void ProcessLimiter(unsigned int samples, float gain);
void ProcessOutput(void* out, unsigned int samples, float gain);
public:
CPCMRemap();
~CPCMRemap();
void Reset();
enum PCMChannels *SetInputFormat (unsigned int channels, enum PCMChannels *channelMap, unsigned int sampleSize, unsigned int sampleRate);
void SetOutputFormat(unsigned int channels, enum PCMChannels *channelMap, bool ignoreLayout = false);
void Remap(void *data, void *out, unsigned int samples, long drc);
void Remap(void *data, void *out, unsigned int samples, float gain = 1.0f);
bool CanRemap();
int InBytesToFrames (int bytes );
int FramesToOutBytes(int frames);
int FramesToInBytes (int frames);
float GetCurrentAttenuation() { return m_attenuationMin; }
};
#endif

266
utils/RegExp.cpp Normal file
View file

@ -0,0 +1,266 @@
/*
* Copyright (C) 2005-2008 Team XBMC
* http://www.xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with XBMC; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#include <stdlib.h>
#include <string.h>
#include "RegExp.h"
#include "StdString.h"
#include "log.h"
using namespace PCRE;
CRegExp::CRegExp(bool caseless)
{
m_re = NULL;
m_iOptions = PCRE_DOTALL;
if(caseless)
m_iOptions |= PCRE_CASELESS;
m_bMatched = false;
m_iMatchCount = 0;
}
CRegExp::CRegExp(const CRegExp& re)
{
m_re = NULL;
m_iOptions = re.m_iOptions;
*this = re;
}
const CRegExp& CRegExp::operator=(const CRegExp& re)
{
size_t size;
Cleanup();
m_pattern = re.m_pattern;
if (re.m_re)
{
if (pcre_fullinfo(re.m_re, NULL, PCRE_INFO_SIZE, &size) >= 0)
{
if ((m_re = (pcre*)malloc(size)))
{
memcpy(m_re, re.m_re, size);
memcpy(m_iOvector, re.m_iOvector, OVECCOUNT*sizeof(int));
m_iMatchCount = re.m_iMatchCount;
m_bMatched = re.m_bMatched;
m_subject = re.m_subject;
m_iOptions = re.m_iOptions;
}
}
}
return *this;
}
CRegExp::~CRegExp()
{
Cleanup();
}
CRegExp* CRegExp::RegComp(const char *re)
{
if (!re)
return NULL;
m_bMatched = false;
m_iMatchCount = 0;
const char *errMsg = NULL;
int errOffset = 0;
Cleanup();
m_re = pcre_compile(re, m_iOptions, &errMsg, &errOffset, NULL);
if (!m_re)
{
m_pattern.clear();
CLog::Log(LOGERROR, "PCRE: %s. Compilation failed at offset %d in expression '%s'",
errMsg, errOffset, re);
return NULL;
}
m_pattern = re;
return this;
}
int CRegExp::RegFind(const char* str, int startoffset)
{
m_bMatched = false;
m_iMatchCount = 0;
if (!m_re)
{
CLog::Log(LOGERROR, "PCRE: Called before compilation");
return -1;
}
if (!str)
{
CLog::Log(LOGERROR, "PCRE: Called without a string to match");
return -1;
}
m_subject = str;
int rc = pcre_exec(m_re, NULL, str, strlen(str), startoffset, 0, m_iOvector, OVECCOUNT);
if (rc<1)
{
switch(rc)
{
case PCRE_ERROR_NOMATCH:
return -1;
case PCRE_ERROR_MATCHLIMIT:
CLog::Log(LOGERROR, "PCRE: Match limit reached");
return -1;
default:
CLog::Log(LOGERROR, "PCRE: Unknown error: %d", rc);
return -1;
}
}
m_bMatched = true;
m_iMatchCount = rc;
return m_iOvector[0];
}
int CRegExp::GetCaptureTotal()
{
int c = -1;
if (m_re)
pcre_fullinfo(m_re, NULL, PCRE_INFO_CAPTURECOUNT, &c);
return c;
}
char* CRegExp::GetReplaceString( const char* sReplaceExp )
{
char *src = (char *)sReplaceExp;
char *buf;
char c;
int no;
size_t len;
if( sReplaceExp == NULL || !m_bMatched )
return NULL;
// First compute the length of the string
int replacelen = 0;
while ((c = *src++) != '\0')
{
if (c == '&')
no = 0;
else if (c == '\\' && isdigit(*src))
no = *src++ - '0';
else
no = -1;
if (no < 0)
{
// Ordinary character.
if (c == '\\' && (*src == '\\' || *src == '&'))
c = *src++;
replacelen++;
}
else if (no < m_iMatchCount && (m_iOvector[no*2]>=0))
{
// Get tagged expression
len = m_iOvector[no*2+1] - m_iOvector[no*2];
replacelen += len;
}
}
// Now allocate buf
buf = (char *)malloc((replacelen + 1)*sizeof(char));
if( buf == NULL )
return NULL;
char* sReplaceStr = buf;
// Add null termination
buf[replacelen] = '\0';
// Now we can create the string
src = (char *)sReplaceExp;
while ((c = *src++) != '\0')
{
if (c == '&')
no = 0;
else if (c == '\\' && isdigit(*src))
no = *src++ - '0';
else
no = -1;
if (no < 0)
{
// Ordinary character.
if (c == '\\' && (*src == '\\' || *src == '&'))
c = *src++;
*buf++ = c;
}
else if (no < m_iMatchCount && (m_iOvector[no*2]>=0))
{
// Get tagged expression
len = m_iOvector[no*2+1] - m_iOvector[no*2];
strncpy(buf, m_subject.c_str()+m_iOvector[no*2], len);
buf += len;
}
}
return sReplaceStr;
}
std::string CRegExp::GetMatch(int iSub /* = 0 */)
{
if (iSub < 0 || iSub > m_iMatchCount)
return "";
int pos = m_iOvector[(iSub*2)];
int len = m_iOvector[(iSub*2)+1] - pos;
return m_subject.substr(pos, len);
}
bool CRegExp::GetNamedSubPattern(const char* strName, std::string& strMatch)
{
strMatch.clear();
int iSub = pcre_get_stringnumber(m_re, strName);
if (iSub < 0)
return false;
strMatch = GetMatch(iSub);
return true;
}
void CRegExp::DumpOvector(int iLog /* = LOGDEBUG */)
{
if (iLog < LOGDEBUG || iLog > LOGNONE)
return;
CStdString str = "{";
int size = GetSubCount(); // past the subpatterns is junk
for (int i = 0; i <= size; i++)
{
CStdString t;
t.Format("[%i,%i]", m_iOvector[(i*2)], m_iOvector[(i*2)+1]);
if (i != size)
t += ",";
str += t;
}
str += "}";
CLog::Log(iLog, "regexp ovector=%s", str.c_str());
}

87
utils/RegExp.h Normal file
View file

@ -0,0 +1,87 @@
#pragma once
/*
* Copyright (C) 2005-2008 Team XBMC
* http://www.xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with XBMC; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#ifndef REGEXP_H
#define REGEXP_H
#include <string>
#include <vector>
namespace PCRE {
#ifdef _WIN32
#define PCRE_STATIC
#include "lib/win32/pcre/pcre.h"
#else
#include <pcre.h>
#endif
}
// maximum of 20 backreferences
// OVEVCOUNT must be a multiple of 3
const int OVECCOUNT=(20+1)*3;
class CRegExp
{
public:
CRegExp(bool caseless = false);
CRegExp(const CRegExp& re);
~CRegExp();
CRegExp* RegComp(const char *re);
CRegExp* RegComp(const std::string& re) { return RegComp(re.c_str()); }
int RegFind(const char *str, int startoffset = 0);
int RegFind(const std::string& str, int startoffset = 0) { return RegFind(str.c_str(), startoffset); }
char* GetReplaceString( const char* sReplaceExp );
int GetFindLen()
{
if (!m_re || !m_bMatched)
return 0;
return (m_iOvector[1] - m_iOvector[0]);
};
int GetSubCount() { return m_iMatchCount - 1; } // PCRE returns the number of sub-patterns + 1
int GetSubStart(int iSub) { return m_iOvector[iSub*2]; } // normalized to match old engine
int GetSubLength(int iSub) { return (m_iOvector[(iSub*2)+1] - m_iOvector[(iSub*2)]); } // correct spelling
int GetCaptureTotal();
std::string GetMatch(int iSub = 0);
const std::string& GetPattern() { return m_pattern; }
bool GetNamedSubPattern(const char* strName, std::string& strMatch);
void DumpOvector(int iLog);
const CRegExp& operator= (const CRegExp& re);
private:
void Cleanup() { if (m_re) { PCRE::pcre_free(m_re); m_re = NULL; } }
private:
PCRE::pcre* m_re;
int m_iOvector[OVECCOUNT];
int m_iMatchCount;
int m_iOptions;
bool m_bMatched;
std::string m_subject;
std::string m_pattern;
};
typedef std::vector<CRegExp> VECCREGEXP;
#endif

4344
utils/StdString.h Normal file

File diff suppressed because it is too large Load diff

220
utils/log.cpp Normal file
View file

@ -0,0 +1,220 @@
/*
* Copyright (C) 2005-2008 Team XBMC
* http://www.xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with XBMC; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#include "system.h"
#include "log.h"
#include "stdio_utf8.h"
#include "stat_utf8.h"
#include "utils/StdString.h"
static FILE* m_file = NULL;
static int m_repeatCount = 0;
static int m_repeatLogLevel = -1;
static std::string m_repeatLine = "";
static int m_logLevel = LOG_LEVEL_DEBUG;
static pthread_mutex_t m_log_mutex;
static char levelNames[][8] =
{"DEBUG", "INFO", "NOTICE", "WARNING", "ERROR", "SEVERE", "FATAL", "NONE"};
CLog::CLog()
{}
CLog::~CLog()
{}
void CLog::Close()
{
if (m_file)
{
fclose(m_file);
m_file = NULL;
}
m_repeatLine.clear();
pthread_mutex_destroy(&m_log_mutex);
}
void CLog::Log(int loglevel, const char *format, ... )
{
pthread_mutex_lock(&m_log_mutex);
static const char* prefixFormat = "%02.2d:%02.2d:%02.2d T:%"PRIu64" %7s: ";
#if !(defined(_DEBUG) || defined(PROFILE))
if (m_logLevel > LOG_LEVEL_NORMAL ||
(m_logLevel > LOG_LEVEL_NONE && loglevel >= LOGNOTICE))
#endif
{
if (!m_file)
{
pthread_mutex_unlock(&m_log_mutex);
return;
}
SYSTEMTIME time;
//GetLocalTime(&time);
CStdString strPrefix, strData;
strData.reserve(16384);
va_list va;
va_start(va, format);
strData.FormatV(format,va);
va_end(va);
if (m_repeatLogLevel == loglevel && m_repeatLine == strData)
{
m_repeatCount++;
pthread_mutex_unlock(&m_log_mutex);
return;
}
else if (m_repeatCount)
{
CStdString strData2;
time.wHour = 0;
time.wMinute = 0;
time.wSecond = 0;
strPrefix.Format(prefixFormat, time.wHour, time.wMinute, time.wSecond, (uint64_t)0, levelNames[m_repeatLogLevel]);
strData2.Format("Previous line repeats %d times." LINE_ENDING, m_repeatCount);
fputs(strPrefix.c_str(), m_file);
fputs(strData2.c_str(), m_file);
OutputDebugString(strData2);
m_repeatCount = 0;
}
m_repeatLine = strData;
m_repeatLogLevel = loglevel;
unsigned int length = 0;
while ( length != strData.length() )
{
length = strData.length();
strData.TrimRight(" ");
strData.TrimRight('\n');
strData.TrimRight("\r");
}
if (!length)
{
pthread_mutex_unlock(&m_log_mutex);
return;
}
OutputDebugString(strData);
/* fixup newline alignment, number of spaces should equal prefix length */
strData.Replace("\n", LINE_ENDING" ");
strData += LINE_ENDING;
strPrefix.Format(prefixFormat, time.wHour, time.wMinute, time.wSecond, (uint64_t)0, levelNames[loglevel]);
fputs(strPrefix.c_str(), m_file);
fputs(strData.c_str(), m_file);
//fputs(strPrefix.c_str(), stdout);
//fputs(strData.c_str(), stdout);
fflush(m_file);
}
pthread_mutex_unlock(&m_log_mutex);
}
bool CLog::Init(const char* path)
{
pthread_mutex_init(&m_log_mutex, NULL);
if (!m_file)
{
CStdString strLogFile, strLogFileOld;
strLogFile.Format("omxplayer.log", path);
strLogFileOld.Format("omxplayer.old.log", path);
struct stat info;
if (stat(strLogFileOld.c_str(),&info) == 0 &&
remove(strLogFileOld.c_str()) != 0)
return false;
if (stat(strLogFile.c_str(),&info) == 0 &&
rename(strLogFile.c_str(),strLogFileOld.c_str()) != 0)
return false;
m_file = fopen(strLogFile.c_str(),"wb");
}
if (m_file)
{
unsigned char BOM[3] = {0xEF, 0xBB, 0xBF};
fwrite(BOM, sizeof(BOM), 1, m_file);
}
return m_file != NULL;
}
void CLog::MemDump(char *pData, int length)
{
Log(LOGDEBUG, "MEM_DUMP: Dumping from %p", pData);
for (int i = 0; i < length; i+=16)
{
CStdString strLine;
strLine.Format("MEM_DUMP: %04x ", i);
char *alpha = pData;
for (int k=0; k < 4 && i + 4*k < length; k++)
{
for (int j=0; j < 4 && i + 4*k + j < length; j++)
{
CStdString strFormat;
strFormat.Format(" %02x", *pData++);
strLine += strFormat;
}
strLine += " ";
}
// pad with spaces
while (strLine.size() < 13*4 + 16)
strLine += " ";
for (int j=0; j < 16 && i + j < length; j++)
{
if (*alpha > 31)
strLine += *alpha;
else
strLine += '.';
alpha++;
}
Log(LOGDEBUG, "%s", strLine.c_str());
}
}
void CLog::SetLogLevel(int level)
{
m_logLevel = level;
CLog::Log(LOGNOTICE, "Log level changed to %d", m_logLevel);
}
int CLog::GetLogLevel()
{
return m_logLevel;
}
void CLog::OutputDebugString(const std::string& line)
{
#if defined(_DEBUG) || defined(PROFILE)
::OutputDebugString(line.c_str());
::OutputDebugString("\n");
#endif
}

63
utils/log.h Normal file
View file

@ -0,0 +1,63 @@
#pragma once
/*
* Copyright (C) 2005-2008 Team XBMC
* http://www.xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with XBMC; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#include <stdio.h>
#include <string>
#define LOG_LEVEL_NONE -1 // nothing at all is logged
#define LOG_LEVEL_NORMAL 0 // shows notice, error, severe and fatal
#define LOG_LEVEL_DEBUG 1 // shows all
#define LOG_LEVEL_DEBUG_FREEMEM 2 // shows all + shows freemem on screen
#define LOG_LEVEL_DEBUG_SAMBA 3 // shows all + freemem on screen + samba debugging
#define LOG_LEVEL_MAX LOG_LEVEL_DEBUG_SAMBA
// ones we use in the code
#define LOGDEBUG 0
#define LOGINFO 1
#define LOGNOTICE 2
#define LOGWARNING 3
#define LOGERROR 4
#define LOGSEVERE 5
#define LOGFATAL 6
#define LOGNONE 7
#ifdef __GNUC__
#define ATTRIB_LOG_FORMAT __attribute__((format(printf,2,3)))
#else
#define ATTRIB_LOG_FORMAT
#endif
class CLog
{
public:
CLog();
virtual ~CLog(void);
static void Close();
static void Log(int loglevel, const char *format, ... ) ATTRIB_LOG_FORMAT;
static void MemDump(char *pData, int length);
static bool Init(const char* path);
static void SetLogLevel(int level);
static int GetLogLevel();
private:
static void OutputDebugString(const std::string& line);
};