vlc | branch: master | Francois Cartegnie <[email protected]> | Fri Jan 22 22:38:40 2016 +0100| [164ef9f2589619cd84d6b30ac78a6fadd4c98c63] | committer: Francois Cartegnie
codecs: add ATSC A65 helpers > http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=164ef9f2589619cd84d6b30ac78a6fadd4c98c63 --- modules/codec/atsc_a65.c | 244 ++++++++++++++++++++++++++++++++++++++++++++++ modules/codec/atsc_a65.h | 29 ++++++ 2 files changed, 273 insertions(+) diff --git a/modules/codec/atsc_a65.c b/modules/codec/atsc_a65.c new file mode 100644 index 0000000..081bd7f --- /dev/null +++ b/modules/codec/atsc_a65.c @@ -0,0 +1,244 @@ +/***************************************************************************** + * atsc_a65.c : ATSC A65 decoding helpers + ***************************************************************************** + * Copyright (C) 2016 - VideoLAN Authors + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + *****************************************************************************/ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include <vlc_common.h> +#include <vlc_charset.h> + +#include "atsc_a65.h" + +enum +{ + ATSC_A65_COMPRESSION_NONE = 0x00, + ATSC_A65_COMPRESSION_HUFFMAN_C4C5 = 0x01, + ATSC_A65_COMPRESSION_HUFFMAN_C6C7 = 0x02, + ATSC_A65_COMPRESSION_RESERVED_FIRST = 0x03, + ATSC_A65_COMPRESSION_RESERVED_LAST = 0xAF, + ATSC_A65_COMPRESSION_OTHER_FIRST = 0xB0, + ATSC_A65_COMPRESSION_OTHER_LAST = 0xFF, +}; + +enum +{ + ATSC_A65_MODE_UNICODE_RANGE_START = 0x00, /* See reserved ranges */ + ATSC_A65_MODE_UNICODE_RANGE_END = 0x33, + ATSC_A65_MODE_SCSU = 0x3E, + ATSC_A65_MODE_UNICODE_UTF16 = 0x3F, + ATSC_A65_MODE_TAIWAN_FIRST = 0x40, + ATSC_A65_MODE_TAIWAN_LAST = 0x41, + ATSC_A65_MODE_SOUTH_KOREA = 0x48, + ATSC_A65_MODE_OTHER_FIRST = 0xE0, + ATSC_A65_MODE_OTHER_LAST = 0xFE, + ATSC_A65_MODE_NOT_APPLICABLE = 0xFF, +}; + +const uint8_t ATSC_A65_MODE_RESERVED_RANGES[12] = { + /* start, end */ + 0x07, 0x08, + 0x11, 0x1F, + 0x28, 0x2F, + 0x34, 0x3D, + 0x42, 0x47, + 0x49, 0xDF, +}; + +struct atsc_a65_handle_t +{ + char *psz_lang; + vlc_iconv_t iconv16; +}; + +atsc_a65_handle_t *atsc_a65_handle_New( const char *psz_lang ) +{ + atsc_a65_handle_t *p_handle = malloc( sizeof(*p_handle) ); + if( p_handle ) + { + if( psz_lang && strlen(psz_lang) > 2 ) + p_handle->psz_lang = strdup( psz_lang ); + else + p_handle->psz_lang = NULL; + + p_handle->iconv16 = NULL; + } + return p_handle; +} + +void atsc_a65_handle_Release( atsc_a65_handle_t *p_handle ) +{ + if( p_handle->iconv16 ) + vlc_iconv_close( p_handle->iconv16 ); + free( p_handle->psz_lang ); + free( p_handle ); +} + +static char *enlarge_to16( const uint8_t *p_src, size_t i_src, uint8_t i_prefix ) +{ + if( i_src == 0 ) + return NULL; + + char *psz_new = malloc( i_src * 2 + 1 ); + if( psz_new ) + { + memset( psz_new, i_prefix, i_src * 2 ); + psz_new[ i_src * 2 ] = 0; + while( *p_src ) + { + psz_new[1] = p_src[0]; + p_src++; + psz_new += 2; + } + } + return psz_new; +} + +static bool convert_encoding_set( atsc_a65_handle_t *p_handle, + const uint8_t *p_src, size_t i_src, + char **ppsz_merg, size_t *pi_mergmin1, + uint8_t i_mode ) +{ + char *psz_dest = *ppsz_merg; + size_t i_mergmin1 = *pi_mergmin1; + bool b_ret = true; + + /* First exclude reserved ranges */ + for( unsigned i=0; i<12; i+=2 ) + { + if( i_mode >= ATSC_A65_MODE_RESERVED_RANGES[i] && + i_mode <= ATSC_A65_MODE_RESERVED_RANGES[i+1] ) + return false; + } + + if( i_mode == ATSC_A65_MODE_UNICODE_RANGE_START ) /* Latin 1 */ + { + char *psz_realloc = realloc( psz_dest, i_mergmin1 + i_src + 1 ); + if( psz_realloc ) + { + psz_realloc[i_mergmin1 + i_src] = 0; + memcpy( &psz_realloc[i_mergmin1], p_src, i_src ); + psz_dest = psz_realloc; + i_mergmin1 += i_src; + } + else return false; + } + else if( i_mode > ATSC_A65_MODE_UNICODE_RANGE_START && /* 8 range prefix + 8 */ + i_mode <= ATSC_A65_MODE_UNICODE_RANGE_END ) + { + if( !p_handle->iconv16 ) + { + if ( !(p_handle->iconv16 = vlc_iconv_open("UTF-8", "UCS-2BE")) ) + return false; + } + else if ( VLC_ICONV_ERR == vlc_iconv( p_handle->iconv16, NULL, NULL, NULL, NULL ) ) /* reset */ + { + return false; + } + + char *psz16 = enlarge_to16( p_src, i_src, i_mode ); /* Maybe we can skip and feed iconv 2 by 2 */ + if( psz16 ) + { + char *psz_realloc = realloc( psz_dest, i_mergmin1 + (4 * i_src) + 1 ); + if( psz_realloc ) + { + const char *p_inbuf = psz16; + char *p_outbuf = &psz_realloc[i_mergmin1]; + size_t i_inbuf = i_src * 2; + size_t i_outbuf = i_src * 4; + b_ret = ( VLC_ICONV_ERR != vlc_iconv( p_handle->iconv16, &p_inbuf, &i_inbuf, + &p_outbuf, &i_outbuf ) ); + psz_dest = psz_realloc; + i_mergmin1 += i_outbuf; + psz_dest[i_mergmin1] = 0; + } + free( psz16 ); + } + else return false; + } + else + { + /* Unsupported encodings */ + return false; + } + + *ppsz_merg = psz_dest; + *pi_mergmin1 = i_mergmin1; + return b_ret; +} + +#define BUF_ADVANCE(n) p_buffer += n; i_buffer -= n; + +char * atsc_a65_Decode_multiple_string( atsc_a65_handle_t *p_handle, const uint8_t *p_buffer, size_t i_buffer ) +{ + char *psz_res = NULL; + size_t i_resmin1 = 0; + + if( i_buffer < 1 ) + return NULL; + + uint8_t i_nb = p_buffer[0]; + BUF_ADVANCE(1); + + for( ; i_nb > 0; i_nb-- ) + { + if( i_buffer < 4 ) + goto error; + + bool b_skip = ( p_handle->psz_lang && memcmp(p_buffer, p_handle->psz_lang, 3) ); + BUF_ADVANCE(3); + + uint8_t i_seg = p_buffer[0]; + BUF_ADVANCE(1); + for( ; i_seg > 0; i_seg-- ) + { + if( i_buffer < 3 ) + goto error; + + const uint8_t i_compression = p_buffer[0]; + const uint8_t i_mode = p_buffer[1]; + const uint8_t i_bytes = p_buffer[2]; + BUF_ADVANCE(3); + + if( i_buffer < i_bytes ) + goto error; + + if( i_compression != ATSC_A65_COMPRESSION_NONE ) // TBD + { + b_skip = true; + } + + if( !b_skip ) + { + (void) convert_encoding_set( p_handle, p_buffer, i_bytes, + &psz_res, &i_resmin1, i_mode ); + } + + BUF_ADVANCE(i_bytes); + } + } + + return psz_res; + +error: + free( psz_res ); + return NULL; +} + +#undef BUF_ADVANCE diff --git a/modules/codec/atsc_a65.h b/modules/codec/atsc_a65.h new file mode 100644 index 0000000..c4866f8 --- /dev/null +++ b/modules/codec/atsc_a65.h @@ -0,0 +1,29 @@ +/***************************************************************************** + * atsc_a65.h : ATSC A65 decoding helpers + ***************************************************************************** + * Copyright (C) 2016 - VideoLAN Authors + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + *****************************************************************************/ +#ifndef VLC_ATSC_A65_H +#define VLC_ATSC_A65_H + +typedef struct atsc_a65_handle_t atsc_a65_handle_t; + +atsc_a65_handle_t *atsc_a65_handle_New( const char *psz_lang ); +void atsc_a65_handle_Release( atsc_a65_handle_t * ); + +char * atsc_a65_Decode_multiple_string( atsc_a65_handle_t *, const uint8_t *, size_t ); + +#endif _______________________________________________ vlc-commits mailing list [email protected] https://mailman.videolan.org/listinfo/vlc-commits
