2005-07-17 03:28:12 +03:00
/*
2011-10-30 19:56:57 +03:00
* DVB subtitle decoding
2009-01-19 17:46:40 +02:00
* Copyright ( c ) 2005 Ian Caulfield
2005-07-17 03:28:12 +03:00
*
2006-10-07 18:30:46 +03:00
* This file is part of FFmpeg .
*
* FFmpeg is free software ; you can redistribute it and / or
2005-07-17 03:28:12 +03:00
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation ; either
2006-10-07 18:30:46 +03:00
* version 2.1 of the License , or ( at your option ) any later version .
2005-07-17 03:28:12 +03:00
*
2006-10-07 18:30:46 +03:00
* FFmpeg is distributed in the hope that it will be useful ,
2005-07-17 03:28:12 +03:00
* 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 Lesser General Public
2006-10-07 18:30:46 +03:00
* License along with FFmpeg ; if not , write to the Free Software
2006-01-13 00:43:26 +02:00
* Foundation , Inc . , 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 USA
2005-07-17 03:28:12 +03:00
*/
2014-03-26 14:41:22 +03:00
2005-07-17 03:28:12 +03:00
# include "avcodec.h"
2009-04-13 19:20:26 +03:00
# include "get_bits.h"
2010-06-16 16:07:12 +03:00
# include "bytestream.h"
2015-03-16 10:57:36 +02:00
# include "internal.h"
2010-07-01 21:49:44 +03:00
# include "libavutil/colorspace.h"
2017-05-08 15:17:31 +02:00
# include "libavutil/imgutils.h"
2014-06-14 14:36:37 +03:00
# include "libavutil/opt.h"
2005-07-17 03:28:12 +03:00
# define DVBSUB_PAGE_SEGMENT 0x10
# define DVBSUB_REGION_SEGMENT 0x11
# define DVBSUB_CLUT_SEGMENT 0x12
# define DVBSUB_OBJECT_SEGMENT 0x13
2010-06-16 16:07:12 +03:00
# define DVBSUB_DISPLAYDEFINITION_SEGMENT 0x14
2005-07-17 03:28:12 +03:00
# define DVBSUB_DISPLAY_SEGMENT 0x80
2013-12-22 16:32:11 +03:00
# define cm (ff_crop_tab + MAX_NEG_CROP)
2005-07-17 03:28:12 +03:00
2012-02-03 14:06:37 +03:00
# define RGBA(r,g,b,a) (((unsigned)(a) << 24) | ((r) << 16) | ((g) << 8) | (b))
2005-07-17 03:28:12 +03:00
typedef struct DVBSubCLUT {
int id ;
2011-10-14 17:41:21 +03:00
int version ;
2005-07-17 03:28:12 +03:00
uint32_t clut4 [ 4 ] ;
uint32_t clut16 [ 16 ] ;
uint32_t clut256 [ 256 ] ;
2005-12-17 20:14:38 +02:00
2005-07-17 03:28:12 +03:00
struct DVBSubCLUT * next ;
} DVBSubCLUT ;
static DVBSubCLUT default_clut ;
typedef struct DVBSubObjectDisplay {
int object_id ;
int region_id ;
int x_pos ;
int y_pos ;
2007-12-03 15:33:48 +02:00
int fgcolor ;
int bgcolor ;
2005-12-17 20:14:38 +02:00
2005-07-17 03:28:12 +03:00
struct DVBSubObjectDisplay * region_list_next ;
2005-12-17 20:14:38 +02:00
struct DVBSubObjectDisplay * object_list_next ;
2005-07-17 03:28:12 +03:00
} DVBSubObjectDisplay ;
typedef struct DVBSubObject {
int id ;
2011-10-14 17:41:21 +03:00
int version ;
2005-07-17 03:28:12 +03:00
int type ;
2005-12-17 20:14:38 +02:00
DVBSubObjectDisplay * display_list ;
2005-07-17 03:28:12 +03:00
struct DVBSubObject * next ;
} DVBSubObject ;
typedef struct DVBSubRegionDisplay {
int region_id ;
int x_pos ;
int y_pos ;
struct DVBSubRegionDisplay * next ;
} DVBSubRegionDisplay ;
typedef struct DVBSubRegion {
int id ;
2011-10-14 17:41:21 +03:00
int version ;
2005-07-17 03:28:12 +03:00
int width ;
int height ;
int depth ;
2005-12-17 20:14:38 +02:00
2005-07-17 03:28:12 +03:00
int clut ;
2007-12-03 15:33:48 +02:00
int bgcolor ;
2005-12-17 20:14:38 +02:00
2005-07-17 03:28:12 +03:00
uint8_t * pbuf ;
int buf_size ;
2011-10-14 16:28:50 +03:00
int dirty ;
2005-07-17 03:28:12 +03:00
DVBSubObjectDisplay * display_list ;
2005-12-17 20:14:38 +02:00
2005-07-17 03:28:12 +03:00
struct DVBSubRegion * next ;
} DVBSubRegion ;
2010-06-16 16:07:12 +03:00
typedef struct DVBSubDisplayDefinition {
int version ;
int x ;
int y ;
int width ;
int height ;
} DVBSubDisplayDefinition ;
2005-07-17 03:28:12 +03:00
typedef struct DVBSubContext {
2014-06-14 14:36:37 +03:00
AVClass * class ;
2005-07-17 03:28:12 +03:00
int composition_id ;
int ancillary_id ;
2011-10-14 17:41:21 +03:00
int version ;
2005-07-17 03:28:12 +03:00
int time_out ;
2014-06-22 10:24:33 +03:00
int compute_edt ; /**< if 1 end display time calculated using pts
if 0 ( Default ) calculated using time out */
2015-07-26 18:38:18 +02:00
int compute_clut ;
2015-07-27 16:31:05 +02:00
int substream ;
2014-06-22 10:24:33 +03:00
int64_t prev_start ;
2005-07-17 03:28:12 +03:00
DVBSubRegion * region_list ;
DVBSubCLUT * clut_list ;
DVBSubObject * object_list ;
2005-12-17 20:14:38 +02:00
2005-07-17 03:28:12 +03:00
DVBSubRegionDisplay * display_list ;
2010-06-16 16:07:12 +03:00
DVBSubDisplayDefinition * display_definition ;
2005-07-17 03:28:12 +03:00
} DVBSubContext ;
static DVBSubObject * get_object ( DVBSubContext * ctx , int object_id )
{
DVBSubObject * ptr = ctx - > object_list ;
2007-11-19 22:26:35 +02:00
while ( ptr & & ptr - > id ! = object_id ) {
2005-07-17 03:28:12 +03:00
ptr = ptr - > next ;
}
2005-12-17 20:14:38 +02:00
2005-07-17 03:28:12 +03:00
return ptr ;
}
static DVBSubCLUT * get_clut ( DVBSubContext * ctx , int clut_id )
{
DVBSubCLUT * ptr = ctx - > clut_list ;
2007-11-19 22:26:35 +02:00
while ( ptr & & ptr - > id ! = clut_id ) {
2005-07-17 03:28:12 +03:00
ptr = ptr - > next ;
}
2005-12-17 20:14:38 +02:00
2005-07-17 03:28:12 +03:00
return ptr ;
}
static DVBSubRegion * get_region ( DVBSubContext * ctx , int region_id )
{
DVBSubRegion * ptr = ctx - > region_list ;
2007-11-19 22:26:35 +02:00
while ( ptr & & ptr - > id ! = region_id ) {
2005-07-17 03:28:12 +03:00
ptr = ptr - > next ;
}
2005-12-17 20:14:38 +02:00
2005-07-17 03:28:12 +03:00
return ptr ;
}
static void delete_region_display_list ( DVBSubContext * ctx , DVBSubRegion * region )
{
DVBSubObject * object , * obj2 , * * obj2_ptr ;
DVBSubObjectDisplay * display , * obj_disp , * * obj_disp_ptr ;
2007-11-19 22:26:35 +02:00
while ( region - > display_list ) {
2005-07-17 03:28:12 +03:00
display = region - > display_list ;
2005-12-17 20:14:38 +02:00
2005-07-17 03:28:12 +03:00
object = get_object ( ctx , display - > object_id ) ;
2005-12-17 20:14:38 +02:00
2007-11-19 22:26:35 +02:00
if ( object ) {
2005-07-17 03:28:12 +03:00
obj_disp_ptr = & object - > display_list ;
2008-05-28 04:34:46 +03:00
obj_disp = * obj_disp_ptr ;
2005-12-17 20:14:38 +02:00
2007-11-19 22:26:35 +02:00
while ( obj_disp & & obj_disp ! = display ) {
2005-07-17 03:28:12 +03:00
obj_disp_ptr = & obj_disp - > object_list_next ;
2008-05-28 04:34:46 +03:00
obj_disp = * obj_disp_ptr ;
2005-07-17 03:28:12 +03:00
}
2005-12-17 20:14:38 +02:00
2005-07-17 03:28:12 +03:00
if ( obj_disp ) {
* obj_disp_ptr = obj_disp - > object_list_next ;
2005-12-17 20:14:38 +02:00
2007-11-19 22:33:25 +02:00
if ( ! object - > display_list ) {
2005-07-17 03:28:12 +03:00
obj2_ptr = & ctx - > object_list ;
2008-05-28 04:34:46 +03:00
obj2 = * obj2_ptr ;
2005-07-17 03:28:12 +03:00
2008-05-28 04:30:59 +03:00
while ( obj2 ! = object ) {
2014-11-12 19:14:28 +02:00
av_assert0 ( obj2 ) ;
2005-07-17 03:28:12 +03:00
obj2_ptr = & obj2 - > next ;
2008-05-28 04:34:46 +03:00
obj2 = * obj2_ptr ;
2005-07-17 03:28:12 +03:00
}
2005-12-17 20:14:38 +02:00
2005-07-17 03:28:12 +03:00
* obj2_ptr = obj2 - > next ;
2005-12-17 20:14:38 +02:00
2014-10-31 00:29:33 +02:00
av_freep ( & obj2 ) ;
2005-07-17 03:28:12 +03:00
}
}
}
2005-12-17 20:14:38 +02:00
2005-07-17 03:28:12 +03:00
region - > display_list = display - > region_list_next ;
2005-12-17 20:14:38 +02:00
2014-10-31 00:29:33 +02:00
av_freep ( & display ) ;
2005-07-17 03:28:12 +03:00
}
2005-12-17 20:14:38 +02:00
2005-07-17 03:28:12 +03:00
}
2011-05-04 21:44:14 +03:00
static void delete_cluts ( DVBSubContext * ctx )
2005-07-17 03:28:12 +03:00
{
2007-11-19 22:30:00 +02:00
while ( ctx - > clut_list ) {
2014-10-31 00:28:15 +02:00
DVBSubCLUT * clut = ctx - > clut_list ;
2005-07-17 03:28:12 +03:00
ctx - > clut_list = clut - > next ;
2014-10-31 00:29:33 +02:00
av_freep ( & clut ) ;
2005-07-17 03:28:12 +03:00
}
2011-05-04 21:44:14 +03:00
}
2005-07-17 03:28:12 +03:00
2011-05-04 21:44:14 +03:00
static void delete_objects ( DVBSubContext * ctx )
{
while ( ctx - > object_list ) {
2014-10-31 00:28:15 +02:00
DVBSubObject * object = ctx - > object_list ;
2011-05-04 21:44:14 +03:00
ctx - > object_list = object - > next ;
2014-10-31 00:29:33 +02:00
av_freep ( & object ) ;
2011-05-04 21:44:14 +03:00
}
}
static void delete_regions ( DVBSubContext * ctx )
{
while ( ctx - > region_list ) {
2014-10-31 00:28:15 +02:00
DVBSubRegion * region = ctx - > region_list ;
2011-05-04 21:44:14 +03:00
ctx - > region_list = region - > next ;
delete_region_display_list ( ctx , region ) ;
2014-10-31 00:29:33 +02:00
av_freep ( & region - > pbuf ) ;
av_freep ( & region ) ;
2011-05-04 21:44:14 +03:00
}
2005-07-17 03:28:12 +03:00
}
2008-03-21 05:11:20 +02:00
static av_cold int dvbsub_init_decoder ( AVCodecContext * avctx )
2005-07-17 03:28:12 +03:00
{
int i , r , g , b , a = 0 ;
2010-07-11 10:45:42 +03:00
DVBSubContext * ctx = avctx - > priv_data ;
2005-12-17 20:14:38 +02:00
2015-07-27 16:31:05 +02:00
if ( ctx - > substream < 0 ) {
ctx - > composition_id = - 1 ;
ctx - > ancillary_id = - 1 ;
} else if ( ! avctx - > extradata | | ( avctx - > extradata_size < 4 ) | | ( ( avctx - > extradata_size % 5 ! = 0 ) & & ( avctx - > extradata_size ! = 4 ) ) ) {
2014-02-03 15:11:05 +03:00
av_log ( avctx , AV_LOG_WARNING , " Invalid DVB subtitles stream extradata! \n " ) ;
2010-07-14 20:28:40 +03:00
ctx - > composition_id = - 1 ;
ctx - > ancillary_id = - 1 ;
} else {
2015-07-27 16:31:05 +02:00
if ( avctx - > extradata_size > 5 * ctx - > substream + 2 ) {
ctx - > composition_id = AV_RB16 ( avctx - > extradata + 5 * ctx - > substream ) ;
ctx - > ancillary_id = AV_RB16 ( avctx - > extradata + 5 * ctx - > substream + 2 ) ;
} else {
av_log ( avctx , AV_LOG_WARNING , " Selected DVB subtitles sub-stream %d is not available \n " , ctx - > substream ) ;
ctx - > composition_id = AV_RB16 ( avctx - > extradata ) ;
ctx - > ancillary_id = AV_RB16 ( avctx - > extradata + 2 ) ;
2014-02-03 15:11:05 +03:00
}
2010-07-14 20:28:40 +03:00
}
2005-07-17 03:28:12 +03:00
2011-10-14 17:41:21 +03:00
ctx - > version = - 1 ;
2014-06-22 10:24:33 +03:00
ctx - > prev_start = AV_NOPTS_VALUE ;
2011-10-14 17:41:21 +03:00
2005-07-17 03:28:12 +03:00
default_clut . id = - 1 ;
default_clut . next = NULL ;
default_clut . clut4 [ 0 ] = RGBA ( 0 , 0 , 0 , 0 ) ;
default_clut . clut4 [ 1 ] = RGBA ( 255 , 255 , 255 , 255 ) ;
default_clut . clut4 [ 2 ] = RGBA ( 0 , 0 , 0 , 255 ) ;
default_clut . clut4 [ 3 ] = RGBA ( 127 , 127 , 127 , 255 ) ;
default_clut . clut16 [ 0 ] = RGBA ( 0 , 0 , 0 , 0 ) ;
for ( i = 1 ; i < 16 ; i + + ) {
if ( i < 8 ) {
r = ( i & 1 ) ? 255 : 0 ;
g = ( i & 2 ) ? 255 : 0 ;
b = ( i & 4 ) ? 255 : 0 ;
} else {
r = ( i & 1 ) ? 127 : 0 ;
g = ( i & 2 ) ? 127 : 0 ;
b = ( i & 4 ) ? 127 : 0 ;
2005-12-17 20:14:38 +02:00
}
2005-07-17 03:28:12 +03:00
default_clut . clut16 [ i ] = RGBA ( r , g , b , 255 ) ;
}
default_clut . clut256 [ 0 ] = RGBA ( 0 , 0 , 0 , 0 ) ;
for ( i = 1 ; i < 256 ; i + + ) {
if ( i < 8 ) {
r = ( i & 1 ) ? 255 : 0 ;
g = ( i & 2 ) ? 255 : 0 ;
b = ( i & 4 ) ? 255 : 0 ;
a = 63 ;
} else {
switch ( i & 0x88 ) {
case 0x00 :
r = ( ( i & 1 ) ? 85 : 0 ) + ( ( i & 0x10 ) ? 170 : 0 ) ;
g = ( ( i & 2 ) ? 85 : 0 ) + ( ( i & 0x20 ) ? 170 : 0 ) ;
b = ( ( i & 4 ) ? 85 : 0 ) + ( ( i & 0x40 ) ? 170 : 0 ) ;
a = 255 ;
break ;
case 0x08 :
r = ( ( i & 1 ) ? 85 : 0 ) + ( ( i & 0x10 ) ? 170 : 0 ) ;
g = ( ( i & 2 ) ? 85 : 0 ) + ( ( i & 0x20 ) ? 170 : 0 ) ;
b = ( ( i & 4 ) ? 85 : 0 ) + ( ( i & 0x40 ) ? 170 : 0 ) ;
a = 127 ;
break ;
case 0x80 :
r = 127 + ( ( i & 1 ) ? 43 : 0 ) + ( ( i & 0x10 ) ? 85 : 0 ) ;
g = 127 + ( ( i & 2 ) ? 43 : 0 ) + ( ( i & 0x20 ) ? 85 : 0 ) ;
b = 127 + ( ( i & 4 ) ? 43 : 0 ) + ( ( i & 0x40 ) ? 85 : 0 ) ;
a = 255 ;
break ;
case 0x88 :
r = ( ( i & 1 ) ? 43 : 0 ) + ( ( i & 0x10 ) ? 85 : 0 ) ;
g = ( ( i & 2 ) ? 43 : 0 ) + ( ( i & 0x20 ) ? 85 : 0 ) ;
b = ( ( i & 4 ) ? 43 : 0 ) + ( ( i & 0x40 ) ? 85 : 0 ) ;
a = 255 ;
break ;
}
2005-12-17 20:14:38 +02:00
}
2005-07-17 03:28:12 +03:00
default_clut . clut256 [ i ] = RGBA ( r , g , b , a ) ;
}
return 0 ;
}
2008-03-21 05:11:20 +02:00
static av_cold int dvbsub_close_decoder ( AVCodecContext * avctx )
2005-07-17 03:28:12 +03:00
{
2010-07-11 10:45:42 +03:00
DVBSubContext * ctx = avctx - > priv_data ;
2005-07-17 03:28:12 +03:00
DVBSubRegionDisplay * display ;
2011-05-04 21:44:14 +03:00
delete_regions ( ctx ) ;
delete_objects ( ctx ) ;
delete_cluts ( ctx ) ;
av_freep ( & ctx - > display_definition ) ;
2005-12-17 20:14:38 +02:00
2007-11-19 22:30:00 +02:00
while ( ctx - > display_list ) {
2005-07-17 03:28:12 +03:00
display = ctx - > display_list ;
ctx - > display_list = display - > next ;
2005-12-17 20:14:38 +02:00
2014-10-31 00:29:33 +02:00
av_freep ( & display ) ;
2005-07-17 03:28:12 +03:00
}
return 0 ;
}
2014-12-05 21:30:03 +02:00
static int dvbsub_read_2bit_string ( AVCodecContext * avctx ,
uint8_t * destbuf , int dbuf_len ,
2008-02-01 05:26:31 +02:00
const uint8_t * * srcbuf , int buf_size ,
2011-10-14 15:36:56 +03:00
int non_mod , uint8_t * map_table , int x_pos )
2005-07-17 03:28:12 +03:00
{
GetBitContext gb ;
2005-12-17 20:14:38 +02:00
2005-07-17 03:28:12 +03:00
int bits ;
int run_length ;
2011-10-14 15:36:56 +03:00
int pixels_read = x_pos ;
2005-12-17 20:14:38 +02:00
2009-04-13 00:48:43 +03:00
init_get_bits ( & gb , * srcbuf , buf_size < < 3 ) ;
2005-12-17 20:14:38 +02:00
2011-10-14 15:36:56 +03:00
destbuf + = x_pos ;
2009-04-13 00:48:43 +03:00
while ( get_bits_count ( & gb ) < buf_size < < 3 & & pixels_read < dbuf_len ) {
2005-07-17 03:28:12 +03:00
bits = get_bits ( & gb , 2 ) ;
2007-11-19 22:26:35 +02:00
if ( bits ) {
2005-07-17 03:28:12 +03:00
if ( non_mod ! = 1 | | bits ! = 1 ) {
2007-11-19 22:26:35 +02:00
if ( map_table )
2005-07-17 03:28:12 +03:00
* destbuf + + = map_table [ bits ] ;
else
* destbuf + + = bits ;
}
pixels_read + + ;
} else {
2007-08-09 03:13:31 +03:00
bits = get_bits1 ( & gb ) ;
2005-07-17 03:28:12 +03:00
if ( bits = = 1 ) {
run_length = get_bits ( & gb , 3 ) + 3 ;
bits = get_bits ( & gb , 2 ) ;
2005-12-17 20:14:38 +02:00
2005-07-17 03:28:12 +03:00
if ( non_mod = = 1 & & bits = = 1 )
pixels_read + = run_length ;
else {
2007-11-19 22:26:35 +02:00
if ( map_table )
2005-07-17 03:28:12 +03:00
bits = map_table [ bits ] ;
while ( run_length - - > 0 & & pixels_read < dbuf_len ) {
* destbuf + + = bits ;
pixels_read + + ;
}
}
} else {
2007-08-09 03:13:31 +03:00
bits = get_bits1 ( & gb ) ;
2005-07-17 03:28:12 +03:00
if ( bits = = 0 ) {
bits = get_bits ( & gb , 2 ) ;
if ( bits = = 2 ) {
run_length = get_bits ( & gb , 4 ) + 12 ;
bits = get_bits ( & gb , 2 ) ;
if ( non_mod = = 1 & & bits = = 1 )
pixels_read + = run_length ;
else {
2007-11-19 22:26:35 +02:00
if ( map_table )
2005-07-17 03:28:12 +03:00
bits = map_table [ bits ] ;
while ( run_length - - > 0 & & pixels_read < dbuf_len ) {
* destbuf + + = bits ;
pixels_read + + ;
}
}
} else if ( bits = = 3 ) {
run_length = get_bits ( & gb , 8 ) + 29 ;
bits = get_bits ( & gb , 2 ) ;
if ( non_mod = = 1 & & bits = = 1 )
pixels_read + = run_length ;
else {
2007-11-19 22:26:35 +02:00
if ( map_table )
2005-07-17 03:28:12 +03:00
bits = map_table [ bits ] ;
while ( run_length - - > 0 & & pixels_read < dbuf_len ) {
* destbuf + + = bits ;
pixels_read + + ;
}
}
} else if ( bits = = 1 ) {
2007-11-19 22:26:35 +02:00
if ( map_table )
2005-07-17 03:28:12 +03:00
bits = map_table [ 0 ] ;
else
bits = 0 ;
2011-10-14 15:52:33 +03:00
run_length = 2 ;
while ( run_length - - > 0 & & pixels_read < dbuf_len ) {
2005-07-17 03:28:12 +03:00
* destbuf + + = bits ;
2011-10-14 15:52:33 +03:00
pixels_read + + ;
2005-07-17 03:28:12 +03:00
}
} else {
( * srcbuf ) + = ( get_bits_count ( & gb ) + 7 ) > > 3 ;
return pixels_read ;
}
} else {
2007-11-19 22:26:35 +02:00
if ( map_table )
2005-07-17 03:28:12 +03:00
bits = map_table [ 0 ] ;
else
bits = 0 ;
* destbuf + + = bits ;
pixels_read + + ;
}
}
}
}
2005-12-17 20:14:38 +02:00
2007-11-19 22:26:35 +02:00
if ( get_bits ( & gb , 6 ) )
2014-12-06 03:03:08 +02:00
av_log ( avctx , AV_LOG_ERROR , " line overflow \n " ) ;
2005-07-17 03:28:12 +03:00
( * srcbuf ) + = ( get_bits_count ( & gb ) + 7 ) > > 3 ;
return pixels_read ;
}
2005-12-17 20:14:38 +02:00
2014-12-05 21:30:03 +02:00
static int dvbsub_read_4bit_string ( AVCodecContext * avctx , uint8_t * destbuf , int dbuf_len ,
2008-02-01 05:26:31 +02:00
const uint8_t * * srcbuf , int buf_size ,
2011-10-14 15:36:56 +03:00
int non_mod , uint8_t * map_table , int x_pos )
2005-07-17 03:28:12 +03:00
{
GetBitContext gb ;
2005-12-17 20:14:38 +02:00
2005-07-17 03:28:12 +03:00
int bits ;
int run_length ;
2011-10-14 15:36:56 +03:00
int pixels_read = x_pos ;
2005-12-17 20:14:38 +02:00
2009-04-13 00:48:43 +03:00
init_get_bits ( & gb , * srcbuf , buf_size < < 3 ) ;
2005-12-17 20:14:38 +02:00
2011-10-14 15:36:56 +03:00
destbuf + = x_pos ;
2009-04-13 00:48:43 +03:00
while ( get_bits_count ( & gb ) < buf_size < < 3 & & pixels_read < dbuf_len ) {
2005-07-17 03:28:12 +03:00
bits = get_bits ( & gb , 4 ) ;
2007-11-19 22:26:35 +02:00
if ( bits ) {
2005-07-17 03:28:12 +03:00
if ( non_mod ! = 1 | | bits ! = 1 ) {
2007-11-19 22:26:35 +02:00
if ( map_table )
2005-07-17 03:28:12 +03:00
* destbuf + + = map_table [ bits ] ;
else
* destbuf + + = bits ;
}
pixels_read + + ;
} else {
2007-08-09 03:13:31 +03:00
bits = get_bits1 ( & gb ) ;
2005-07-17 03:28:12 +03:00
if ( bits = = 0 ) {
run_length = get_bits ( & gb , 3 ) ;
2005-12-17 20:14:38 +02:00
2005-07-17 03:28:12 +03:00
if ( run_length = = 0 ) {
( * srcbuf ) + = ( get_bits_count ( & gb ) + 7 ) > > 3 ;
return pixels_read ;
}
2005-12-17 20:14:38 +02:00
2005-07-17 03:28:12 +03:00
run_length + = 2 ;
2005-12-17 20:14:38 +02:00
2007-11-19 22:26:35 +02:00
if ( map_table )
2005-07-17 03:28:12 +03:00
bits = map_table [ 0 ] ;
else
bits = 0 ;
2005-12-17 20:14:38 +02:00
2005-07-17 03:28:12 +03:00
while ( run_length - - > 0 & & pixels_read < dbuf_len ) {
* destbuf + + = bits ;
pixels_read + + ;
}
} else {
2007-08-09 03:13:31 +03:00
bits = get_bits1 ( & gb ) ;
2005-07-17 03:28:12 +03:00
if ( bits = = 0 ) {
run_length = get_bits ( & gb , 2 ) + 4 ;
bits = get_bits ( & gb , 4 ) ;
if ( non_mod = = 1 & & bits = = 1 )
pixels_read + = run_length ;
else {
2007-11-19 22:26:35 +02:00
if ( map_table )
2005-07-17 03:28:12 +03:00
bits = map_table [ bits ] ;
while ( run_length - - > 0 & & pixels_read < dbuf_len ) {
* destbuf + + = bits ;
pixels_read + + ;
}
}
} else {
bits = get_bits ( & gb , 2 ) ;
if ( bits = = 2 ) {
run_length = get_bits ( & gb , 4 ) + 9 ;
bits = get_bits ( & gb , 4 ) ;
2005-12-17 20:14:38 +02:00
2005-07-17 03:28:12 +03:00
if ( non_mod = = 1 & & bits = = 1 )
pixels_read + = run_length ;
else {
2007-11-19 22:26:35 +02:00
if ( map_table )
2005-07-17 03:28:12 +03:00
bits = map_table [ bits ] ;
while ( run_length - - > 0 & & pixels_read < dbuf_len ) {
* destbuf + + = bits ;
pixels_read + + ;
}
}
} else if ( bits = = 3 ) {
run_length = get_bits ( & gb , 8 ) + 25 ;
bits = get_bits ( & gb , 4 ) ;
if ( non_mod = = 1 & & bits = = 1 )
pixels_read + = run_length ;
else {
2007-11-19 22:26:35 +02:00
if ( map_table )
2005-07-17 03:28:12 +03:00
bits = map_table [ bits ] ;
while ( run_length - - > 0 & & pixels_read < dbuf_len ) {
* destbuf + + = bits ;
pixels_read + + ;
}
}
} else if ( bits = = 1 ) {
2007-11-19 22:26:35 +02:00
if ( map_table )
2005-07-17 03:28:12 +03:00
bits = map_table [ 0 ] ;
else
bits = 0 ;
2011-10-14 15:52:33 +03:00
run_length = 2 ;
while ( run_length - - > 0 & & pixels_read < dbuf_len ) {
2005-07-17 03:28:12 +03:00
* destbuf + + = bits ;
2011-10-14 15:52:33 +03:00
pixels_read + + ;
2005-07-17 03:28:12 +03:00
}
} else {
2007-11-19 22:26:35 +02:00
if ( map_table )
2005-07-17 03:28:12 +03:00
bits = map_table [ 0 ] ;
else
bits = 0 ;
* destbuf + + = bits ;
pixels_read + + ;
}
}
}
}
}
2005-12-17 20:14:38 +02:00
2007-11-19 22:26:35 +02:00
if ( get_bits ( & gb , 8 ) )
2014-12-06 03:03:08 +02:00
av_log ( avctx , AV_LOG_ERROR , " line overflow \n " ) ;
2005-12-17 20:14:38 +02:00
2005-07-17 03:28:12 +03:00
( * srcbuf ) + = ( get_bits_count ( & gb ) + 7 ) > > 3 ;
return pixels_read ;
}
2005-12-17 20:14:38 +02:00
2014-12-05 21:30:03 +02:00
static int dvbsub_read_8bit_string ( AVCodecContext * avctx ,
uint8_t * destbuf , int dbuf_len ,
2008-02-01 05:26:31 +02:00
const uint8_t * * srcbuf , int buf_size ,
2011-10-14 15:36:56 +03:00
int non_mod , uint8_t * map_table , int x_pos )
2005-07-17 03:28:12 +03:00
{
2008-02-01 05:26:31 +02:00
const uint8_t * sbuf_end = ( * srcbuf ) + buf_size ;
2005-07-17 03:28:12 +03:00
int bits ;
int run_length ;
2011-10-14 15:36:56 +03:00
int pixels_read = x_pos ;
destbuf + = x_pos ;
2005-12-17 20:14:38 +02:00
2005-07-17 03:28:12 +03:00
while ( * srcbuf < sbuf_end & & pixels_read < dbuf_len ) {
bits = * ( * srcbuf ) + + ;
2005-12-17 20:14:38 +02:00
2007-11-19 22:26:35 +02:00
if ( bits ) {
2005-07-17 03:28:12 +03:00
if ( non_mod ! = 1 | | bits ! = 1 ) {
2007-11-19 22:26:35 +02:00
if ( map_table )
2005-07-17 03:28:12 +03:00
* destbuf + + = map_table [ bits ] ;
else
* destbuf + + = bits ;
}
pixels_read + + ;
} else {
bits = * ( * srcbuf ) + + ;
run_length = bits & 0x7f ;
if ( ( bits & 0x80 ) = = 0 ) {
if ( run_length = = 0 ) {
return pixels_read ;
}
2005-12-17 20:14:38 +02:00
2014-11-12 00:06:44 +02:00
bits = 0 ;
2005-07-17 03:28:12 +03:00
} else {
bits = * ( * srcbuf ) + + ;
2014-11-09 09:48:45 +02:00
}
2014-11-12 00:06:44 +02:00
if ( non_mod = = 1 & & bits = = 1 )
pixels_read + = run_length ;
else {
2007-11-19 22:26:35 +02:00
if ( map_table )
2014-11-12 00:06:44 +02:00
bits = map_table [ bits ] ;
2005-07-17 03:28:12 +03:00
while ( run_length - - > 0 & & pixels_read < dbuf_len ) {
* destbuf + + = bits ;
pixels_read + + ;
}
}
}
}
2005-12-17 20:14:38 +02:00
2007-11-19 22:26:35 +02:00
if ( * ( * srcbuf ) + + )
2014-12-06 03:03:08 +02:00
av_log ( avctx , AV_LOG_ERROR , " line overflow \n " ) ;
2005-12-17 20:14:38 +02:00
2005-07-17 03:28:12 +03:00
return pixels_read ;
}
2005-12-17 20:14:38 +02:00
2015-10-22 21:18:03 +02:00
static void compute_default_clut ( AVSubtitleRect * rect , int w , int h )
2015-07-26 14:22:41 +02:00
{
uint8_t list [ 256 ] = { 0 } ;
uint8_t list_inv [ 256 ] ;
int counttab [ 256 ] = { 0 } ;
int count , i , x , y ;
2015-10-22 21:18:03 +02:00
# define V(x,y) rect->data[0][(x) + (y)*rect->linesize[0]]
2015-07-26 14:22:41 +02:00
for ( y = 0 ; y < h ; y + + ) {
for ( x = 0 ; x < w ; x + + ) {
int v = V ( x , y ) + 1 ;
int vl = x ? V ( x - 1 , y ) + 1 : 0 ;
int vr = x + 1 < w ? V ( x + 1 , y ) + 1 : 0 ;
int vt = y ? V ( x , y - 1 ) + 1 : 0 ;
int vb = y + 1 < h ? V ( x , y + 1 ) + 1 : 0 ;
counttab [ v - 1 ] + = ! ! ( ( v ! = vl ) + ( v ! = vr ) + ( v ! = vt ) + ( v ! = vb ) ) ;
}
}
2015-10-22 21:18:03 +02:00
# define L(x,y) list[ rect->data[0][(x) + (y)*rect->linesize[0]] ]
2015-07-26 14:22:41 +02:00
for ( i = 0 ; i < 256 ; i + + ) {
int scoretab [ 256 ] = { 0 } ;
int bestscore = 0 ;
int bestv = 0 ;
for ( y = 0 ; y < h ; y + + ) {
for ( x = 0 ; x < w ; x + + ) {
2015-10-22 21:18:03 +02:00
int v = rect - > data [ 0 ] [ x + y * rect - > linesize [ 0 ] ] ;
2015-07-26 14:22:41 +02:00
int l_m = list [ v ] ;
int l_l = x ? L ( x - 1 , y ) : 1 ;
int l_r = x + 1 < w ? L ( x + 1 , y ) : 1 ;
int l_t = y ? L ( x , y - 1 ) : 1 ;
int l_b = y + 1 < h ? L ( x , y + 1 ) : 1 ;
int score ;
if ( l_m )
continue ;
scoretab [ v ] + = l_l + l_r + l_t + l_b ;
score = 1024LL * scoretab [ v ] / counttab [ v ] ;
if ( score > bestscore ) {
bestscore = score ;
bestv = v ;
}
}
}
if ( ! bestscore )
break ;
list [ bestv ] = 1 ;
list_inv [ i ] = bestv ;
}
2016-11-08 23:32:42 +02:00
count = FFMAX ( i - 1 , 1 ) ;
2015-07-26 14:22:41 +02:00
for ( i - - ; i > = 0 ; i - - ) {
int v = i * 255 / count ;
2015-10-22 21:18:03 +02:00
AV_WN32 ( rect - > data [ 1 ] + 4 * list_inv [ i ] , RGBA ( v / 2 , v , v / 2 , v ) ) ;
2015-07-26 14:22:41 +02:00
}
}
2014-11-11 23:15:14 +02:00
static int save_subtitle_set ( AVCodecContext * avctx , AVSubtitle * sub , int * got_output )
2014-06-14 14:36:37 +03:00
{
DVBSubContext * ctx = avctx - > priv_data ;
DVBSubRegionDisplay * display ;
DVBSubDisplayDefinition * display_def = ctx - > display_definition ;
DVBSubRegion * region ;
AVSubtitleRect * rect ;
DVBSubCLUT * clut ;
uint32_t * clut_table ;
2016-06-21 22:40:56 +02:00
int i ;
2014-06-14 14:36:37 +03:00
int offset_x = 0 , offset_y = 0 ;
2014-11-12 18:28:53 +02:00
int ret = 0 ;
2014-06-14 14:36:37 +03:00
if ( display_def ) {
offset_x = display_def - > x ;
offset_y = display_def - > y ;
}
2014-06-22 10:24:33 +03:00
/* Not touching AVSubtitles again*/
if ( sub - > num_rects ) {
2015-08-11 22:50:45 +02:00
avpriv_request_sample ( ctx , " Different Version of Segment asked Twice " ) ;
2014-11-11 23:15:14 +02:00
return AVERROR_PATCHWELCOME ;
2014-06-22 10:24:33 +03:00
}
2014-06-14 14:36:37 +03:00
for ( display = ctx - > display_list ; display ; display = display - > next ) {
region = get_region ( ctx , display - > region_id ) ;
if ( region & & region - > dirty )
sub - > num_rects + + ;
}
2014-06-27 13:39:48 +03:00
if ( ctx - > compute_edt = = 0 ) {
sub - > end_display_time = ctx - > time_out * 1000 ;
* got_output = 1 ;
} else if ( ctx - > prev_start ! = AV_NOPTS_VALUE ) {
sub - > end_display_time = av_rescale_q ( ( sub - > pts - ctx - > prev_start ) , AV_TIME_BASE_Q , ( AVRational ) { 1 , 1000 } ) - 1 ;
* got_output = 1 ;
}
2014-06-14 14:36:37 +03:00
if ( sub - > num_rects > 0 ) {
2014-06-22 10:24:33 +03:00
2014-06-14 14:36:37 +03:00
sub - > rects = av_mallocz_array ( sizeof ( * sub - > rects ) , sub - > num_rects ) ;
2014-11-12 18:28:53 +02:00
if ( ! sub - > rects ) {
ret = AVERROR ( ENOMEM ) ;
goto fail ;
}
2014-11-11 23:19:54 +02:00
2014-06-14 14:36:37 +03:00
for ( i = 0 ; i < sub - > num_rects ; i + + )
sub - > rects [ i ] = av_mallocz ( sizeof ( * sub - > rects [ i ] ) ) ;
i = 0 ;
for ( display = ctx - > display_list ; display ; display = display - > next ) {
region = get_region ( ctx , display - > region_id ) ;
if ( ! region )
continue ;
if ( ! region - > dirty )
continue ;
rect = sub - > rects [ i ] ;
rect - > x = display - > x_pos + offset_x ;
rect - > y = display - > y_pos + offset_y ;
rect - > w = region - > width ;
rect - > h = region - > height ;
rect - > nb_colors = ( 1 < < region - > depth ) ;
rect - > type = SUBTITLE_BITMAP ;
2015-10-22 21:18:03 +02:00
rect - > linesize [ 0 ] = region - > width ;
2014-06-14 14:36:37 +03:00
clut = get_clut ( ctx , region - > clut ) ;
if ( ! clut )
clut = & default_clut ;
switch ( region - > depth ) {
case 2 :
clut_table = clut - > clut4 ;
break ;
case 8 :
clut_table = clut - > clut256 ;
break ;
case 4 :
default :
clut_table = clut - > clut16 ;
break ;
}
2005-07-17 03:28:12 +03:00
2015-10-22 21:18:03 +02:00
rect - > data [ 1 ] = av_mallocz ( AVPALETTE_SIZE ) ;
if ( ! rect - > data [ 1 ] ) {
2014-11-12 18:28:53 +02:00
ret = AVERROR ( ENOMEM ) ;
goto fail ;
2014-11-11 23:19:54 +02:00
}
2015-10-22 21:18:03 +02:00
memcpy ( rect - > data [ 1 ] , clut_table , ( 1 < < region - > depth ) * sizeof ( uint32_t ) ) ;
2014-06-14 14:36:37 +03:00
2015-10-22 21:18:03 +02:00
rect - > data [ 0 ] = av_malloc ( region - > buf_size ) ;
if ( ! rect - > data [ 0 ] ) {
2014-11-12 18:28:53 +02:00
ret = AVERROR ( ENOMEM ) ;
goto fail ;
2014-11-11 23:19:54 +02:00
}
2015-10-22 21:18:03 +02:00
memcpy ( rect - > data [ 0 ] , region - > pbuf , region - > buf_size ) ;
2014-06-14 14:36:37 +03:00
2015-07-26 18:38:18 +02:00
if ( ( clut = = & default_clut & & ctx - > compute_clut = = - 1 ) | | ctx - > compute_clut = = 1 )
2015-10-22 21:18:03 +02:00
compute_default_clut ( rect , rect - > w , rect - > h ) ;
# if FF_API_AVPICTURE
FF_DISABLE_DEPRECATION_WARNINGS
2016-06-21 22:40:56 +02:00
{
int j ;
2015-10-22 21:18:03 +02:00
for ( j = 0 ; j < 4 ; j + + ) {
rect - > pict . data [ j ] = rect - > data [ j ] ;
rect - > pict . linesize [ j ] = rect - > linesize [ j ] ;
}
2016-06-21 22:40:56 +02:00
}
2015-10-22 21:18:03 +02:00
FF_ENABLE_DEPRECATION_WARNINGS
# endif
2015-07-26 14:22:41 +02:00
2014-06-14 14:36:37 +03:00
i + + ;
}
}
2014-11-11 23:15:14 +02:00
return 0 ;
2014-11-12 18:28:53 +02:00
fail :
if ( sub - > rects ) {
for ( i = 0 ; i < sub - > num_rects ; i + + ) {
rect = sub - > rects [ i ] ;
if ( rect ) {
2015-10-22 21:18:03 +02:00
av_freep ( & rect - > data [ 0 ] ) ;
av_freep ( & rect - > data [ 1 ] ) ;
2014-11-12 18:28:53 +02:00
}
av_freep ( & sub - > rects [ i ] ) ;
}
av_freep ( & sub - > rects ) ;
}
sub - > num_rects = 0 ;
return ret ;
2014-06-14 14:36:37 +03:00
}
2005-07-17 03:28:12 +03:00
static void dvbsub_parse_pixel_data_block ( AVCodecContext * avctx , DVBSubObjectDisplay * display ,
2008-02-01 05:26:31 +02:00
const uint8_t * buf , int buf_size , int top_bottom , int non_mod )
2005-07-17 03:28:12 +03:00
{
2010-07-11 10:45:42 +03:00
DVBSubContext * ctx = avctx - > priv_data ;
2005-07-17 03:28:12 +03:00
DVBSubRegion * region = get_region ( ctx , display - > region_id ) ;
2008-02-01 05:26:31 +02:00
const uint8_t * buf_end = buf + buf_size ;
2005-07-17 03:28:12 +03:00
uint8_t * pbuf ;
int x_pos , y_pos ;
int i ;
2005-12-17 20:14:38 +02:00
2005-07-17 03:28:12 +03:00
uint8_t map2to4 [ ] = { 0x0 , 0x7 , 0x8 , 0xf } ;
uint8_t map2to8 [ ] = { 0x00 , 0x77 , 0x88 , 0xff } ;
2005-12-17 20:14:38 +02:00
uint8_t map4to8 [ ] = { 0x00 , 0x11 , 0x22 , 0x33 , 0x44 , 0x55 , 0x66 , 0x77 ,
2005-07-17 03:28:12 +03:00
0x88 , 0x99 , 0xaa , 0xbb , 0xcc , 0xdd , 0xee , 0xff } ;
uint8_t * map_table ;
2005-12-17 20:14:38 +02:00
2011-10-14 16:38:55 +03:00
#if 0
2015-03-16 10:57:36 +02:00
ff_dlog ( avctx , " DVB pixel block size %d, %s field: \n " , buf_size ,
2009-07-31 00:00:08 +03:00
top_bottom ? " bottom " : " top " ) ;
2005-07-17 03:28:12 +03:00
2007-11-19 22:30:00 +02:00
for ( i = 0 ; i < buf_size ; i + + ) {
2005-07-17 03:28:12 +03:00
if ( i % 16 = = 0 )
2015-03-16 10:57:36 +02:00
ff_dlog ( avctx , " 0x%8p: " , buf + i ) ;
2005-07-17 03:28:12 +03:00
2015-03-16 10:57:36 +02:00
ff_dlog ( avctx , " %02x " , buf [ i ] ) ;
2005-07-17 03:28:12 +03:00
if ( i % 16 = = 15 )
2015-03-16 10:57:36 +02:00
ff_dlog ( avctx , " \n " ) ;
2005-07-17 03:28:12 +03:00
}
2005-12-17 20:14:38 +02:00
2007-11-19 22:26:35 +02:00
if ( i % 16 )
2015-03-16 10:57:36 +02:00
ff_dlog ( avctx , " \n " ) ;
2011-10-14 16:38:55 +03:00
# endif
2005-07-17 03:28:12 +03:00
2014-08-16 01:41:07 +03:00
if ( ! region )
2005-07-17 03:28:12 +03:00
return ;
2005-12-17 20:14:38 +02:00
2005-07-17 03:28:12 +03:00
pbuf = region - > pbuf ;
2011-10-14 16:28:50 +03:00
region - > dirty = 1 ;
2005-12-17 20:14:38 +02:00
2005-07-17 03:28:12 +03:00
x_pos = display - > x_pos ;
y_pos = display - > y_pos ;
2005-12-17 20:14:38 +02:00
2011-10-14 17:26:38 +03:00
y_pos + = top_bottom ;
2005-07-17 03:28:12 +03:00
while ( buf < buf_end ) {
2011-10-15 22:28:43 +03:00
if ( ( * buf ! = 0xf0 & & x_pos > = region - > width ) | | y_pos > = region - > height ) {
2011-10-14 16:39:33 +03:00
av_log ( avctx , AV_LOG_ERROR , " Invalid object location! %d-%d %d-%d %02x \n " , x_pos , region - > width , y_pos , region - > height , * buf ) ;
2005-07-17 03:28:12 +03:00
return ;
}
2005-12-17 20:14:38 +02:00
2005-07-17 03:28:12 +03:00
switch ( * buf + + ) {
case 0x10 :
if ( region - > depth = = 8 )
map_table = map2to8 ;
else if ( region - > depth = = 4 )
map_table = map2to4 ;
else
map_table = NULL ;
2005-12-17 20:14:38 +02:00
2014-12-05 21:30:03 +02:00
x_pos = dvbsub_read_2bit_string ( avctx , pbuf + ( y_pos * region - > width ) ,
2011-10-14 15:36:56 +03:00
region - > width , & buf , buf_end - buf ,
non_mod , map_table , x_pos ) ;
2005-07-17 03:28:12 +03:00
break ;
case 0x11 :
if ( region - > depth < 4 ) {
av_log ( avctx , AV_LOG_ERROR , " 4-bit pixel string in %d-bit region! \n " , region - > depth ) ;
return ;
}
2005-12-17 20:14:38 +02:00
2005-07-17 03:28:12 +03:00
if ( region - > depth = = 8 )
map_table = map4to8 ;
else
map_table = NULL ;
2005-12-17 20:14:38 +02:00
2014-12-05 21:30:03 +02:00
x_pos = dvbsub_read_4bit_string ( avctx , pbuf + ( y_pos * region - > width ) ,
2011-10-14 15:36:56 +03:00
region - > width , & buf , buf_end - buf ,
non_mod , map_table , x_pos ) ;
2005-07-17 03:28:12 +03:00
break ;
case 0x12 :
if ( region - > depth < 8 ) {
av_log ( avctx , AV_LOG_ERROR , " 8-bit pixel string in %d-bit region! \n " , region - > depth ) ;
return ;
}
2005-12-17 20:14:38 +02:00
2014-12-05 21:30:03 +02:00
x_pos = dvbsub_read_8bit_string ( avctx , pbuf + ( y_pos * region - > width ) ,
2011-10-14 15:36:56 +03:00
region - > width , & buf , buf_end - buf ,
non_mod , NULL , x_pos ) ;
2005-07-17 03:28:12 +03:00
break ;
2005-12-17 20:14:38 +02:00
2005-07-17 03:28:12 +03:00
case 0x20 :
map2to4 [ 0 ] = ( * buf ) > > 4 ;
map2to4 [ 1 ] = ( * buf + + ) & 0xf ;
map2to4 [ 2 ] = ( * buf ) > > 4 ;
map2to4 [ 3 ] = ( * buf + + ) & 0xf ;
break ;
case 0x21 :
for ( i = 0 ; i < 4 ; i + + )
map2to8 [ i ] = * buf + + ;
break ;
case 0x22 :
for ( i = 0 ; i < 16 ; i + + )
map4to8 [ i ] = * buf + + ;
break ;
2005-12-17 20:14:38 +02:00
2005-07-17 03:28:12 +03:00
case 0xf0 :
x_pos = display - > x_pos ;
y_pos + = 2 ;
break ;
default :
av_log ( avctx , AV_LOG_INFO , " Unknown/unsupported pixel block 0x%x \n " , * ( buf - 1 ) ) ;
}
}
2005-12-17 20:14:38 +02:00
2005-07-17 03:28:12 +03:00
}
2014-12-17 17:02:09 +02:00
static int dvbsub_parse_object_segment ( AVCodecContext * avctx ,
const uint8_t * buf , int buf_size )
2005-07-17 03:28:12 +03:00
{
2010-07-11 10:45:42 +03:00
DVBSubContext * ctx = avctx - > priv_data ;
2005-12-17 20:14:38 +02:00
2008-02-01 05:26:31 +02:00
const uint8_t * buf_end = buf + buf_size ;
2005-07-17 03:28:12 +03:00
int object_id ;
DVBSubObject * object ;
DVBSubObjectDisplay * display ;
int top_field_len , bottom_field_len ;
2005-12-17 20:14:38 +02:00
2007-12-03 15:33:48 +02:00
int coding_method , non_modifying_color ;
2005-12-17 20:14:38 +02:00
2007-01-20 00:12:59 +02:00
object_id = AV_RB16 ( buf ) ;
2005-07-17 03:28:12 +03:00
buf + = 2 ;
2005-12-17 20:14:38 +02:00
2005-07-17 03:28:12 +03:00
object = get_object ( ctx , object_id ) ;
2005-12-17 20:14:38 +02:00
if ( ! object )
2014-12-17 17:02:09 +02:00
return AVERROR_INVALIDDATA ;
2005-12-17 20:14:38 +02:00
2005-07-17 03:28:12 +03:00
coding_method = ( ( * buf ) > > 2 ) & 3 ;
2007-12-03 15:33:48 +02:00
non_modifying_color = ( ( * buf + + ) > > 1 ) & 1 ;
2005-12-17 20:14:38 +02:00
2005-07-17 03:28:12 +03:00
if ( coding_method = = 0 ) {
2007-01-20 00:12:59 +02:00
top_field_len = AV_RB16 ( buf ) ;
2005-07-17 03:28:12 +03:00
buf + = 2 ;
2007-01-20 00:12:59 +02:00
bottom_field_len = AV_RB16 ( buf ) ;
2005-07-17 03:28:12 +03:00
buf + = 2 ;
2005-12-17 20:14:38 +02:00
2005-07-17 03:28:12 +03:00
if ( buf + top_field_len + bottom_field_len > buf_end ) {
2015-08-13 01:50:08 +02:00
av_log ( avctx , AV_LOG_ERROR , " Field data size %d+%d too large \n " , top_field_len , bottom_field_len ) ;
2014-12-17 17:02:09 +02:00
return AVERROR_INVALIDDATA ;
2005-12-17 20:14:38 +02:00
}
2007-11-19 22:26:35 +02:00
for ( display = object - > display_list ; display ; display = display - > object_list_next ) {
2011-10-14 16:49:40 +03:00
const uint8_t * block = buf ;
int bfl = bottom_field_len ;
2005-07-17 03:28:12 +03:00
dvbsub_parse_pixel_data_block ( avctx , display , block , top_field_len , 0 ,
2007-12-03 15:33:48 +02:00
non_modifying_color ) ;
2005-07-17 03:28:12 +03:00
if ( bottom_field_len > 0 )
block = buf + top_field_len ;
else
2011-10-14 16:49:40 +03:00
bfl = top_field_len ;
2005-07-17 03:28:12 +03:00
2011-10-14 16:49:40 +03:00
dvbsub_parse_pixel_data_block ( avctx , display , block , bfl , 1 ,
2007-12-03 15:33:48 +02:00
non_modifying_color ) ;
2005-07-17 03:28:12 +03:00
}
2005-12-17 20:14:38 +02:00
2005-07-17 03:28:12 +03:00
/* } else if (coding_method == 1) {*/
2005-12-17 20:14:38 +02:00
2005-07-17 03:28:12 +03:00
} else {
av_log ( avctx , AV_LOG_ERROR , " Unknown object coding %d \n " , coding_method ) ;
}
2005-12-17 20:14:38 +02:00
2014-12-17 17:02:09 +02:00
return 0 ;
2005-07-17 03:28:12 +03:00
}
2013-09-18 20:55:40 +03:00
static int dvbsub_parse_clut_segment ( AVCodecContext * avctx ,
2014-12-17 17:02:09 +02:00
const uint8_t * buf , int buf_size )
2005-07-17 03:28:12 +03:00
{
2010-07-11 10:45:42 +03:00
DVBSubContext * ctx = avctx - > priv_data ;
2005-12-17 20:14:38 +02:00
2008-02-01 05:26:31 +02:00
const uint8_t * buf_end = buf + buf_size ;
2011-06-06 02:25:32 +03:00
int i , clut_id ;
2011-10-14 17:41:21 +03:00
int version ;
2005-07-17 03:28:12 +03:00
DVBSubCLUT * clut ;
int entry_id , depth , full_range ;
int y , cr , cb , alpha ;
int r , g , b , r_add , g_add , b_add ;
2015-03-16 10:57:36 +02:00
ff_dlog ( avctx , " DVB clut packet: \n " ) ;
2005-07-17 03:28:12 +03:00
2007-11-19 22:30:00 +02:00
for ( i = 0 ; i < buf_size ; i + + ) {
2015-03-16 10:57:36 +02:00
ff_dlog ( avctx , " %02x " , buf [ i ] ) ;
2005-07-17 03:28:12 +03:00
if ( i % 16 = = 15 )
2015-03-16 10:57:36 +02:00
ff_dlog ( avctx , " \n " ) ;
2005-07-17 03:28:12 +03:00
}
2005-12-17 20:14:38 +02:00
2007-11-19 22:26:35 +02:00
if ( i % 16 )
2015-03-16 10:57:36 +02:00
ff_dlog ( avctx , " \n " ) ;
2005-07-17 03:28:12 +03:00
clut_id = * buf + + ;
2011-10-14 17:41:21 +03:00
version = ( ( * buf ) > > 4 ) & 15 ;
2005-07-17 03:28:12 +03:00
buf + = 1 ;
2005-12-17 20:14:38 +02:00
2005-07-17 03:28:12 +03:00
clut = get_clut ( ctx , clut_id ) ;
2005-12-17 20:14:38 +02:00
2007-11-19 22:33:25 +02:00
if ( ! clut ) {
2005-07-17 03:28:12 +03:00
clut = av_malloc ( sizeof ( DVBSubCLUT ) ) ;
2015-01-10 20:18:59 +02:00
if ( ! clut )
return AVERROR ( ENOMEM ) ;
2005-12-17 20:14:38 +02:00
2005-07-17 03:28:12 +03:00
memcpy ( clut , & default_clut , sizeof ( DVBSubCLUT ) ) ;
clut - > id = clut_id ;
2011-10-14 17:41:21 +03:00
clut - > version = - 1 ;
2005-12-17 20:14:38 +02:00
clut - > next = ctx - > clut_list ;
2005-07-17 03:28:12 +03:00
ctx - > clut_list = clut ;
}
2005-12-17 20:14:38 +02:00
2011-10-14 17:41:21 +03:00
if ( clut - > version ! = version ) {
clut - > version = version ;
2007-11-19 22:30:00 +02:00
while ( buf + 4 < buf_end ) {
2005-07-17 03:28:12 +03:00
entry_id = * buf + + ;
2005-12-17 20:14:38 +02:00
2005-07-17 03:28:12 +03:00
depth = ( * buf ) & 0xe0 ;
2005-12-17 20:14:38 +02:00
2005-07-17 03:28:12 +03:00
if ( depth = = 0 ) {
av_log ( avctx , AV_LOG_ERROR , " Invalid clut depth 0x%x! \n " , * buf ) ;
}
2005-12-17 20:14:38 +02:00
2005-07-17 03:28:12 +03:00
full_range = ( * buf + + ) & 1 ;
2005-12-17 20:14:38 +02:00
2005-07-17 03:28:12 +03:00
if ( full_range ) {
y = * buf + + ;
cr = * buf + + ;
cb = * buf + + ;
alpha = * buf + + ;
} else {
y = buf [ 0 ] & 0xfc ;
cr = ( ( ( buf [ 0 ] & 3 ) < < 2 ) | ( ( buf [ 1 ] > > 6 ) & 3 ) ) < < 4 ;
cb = ( buf [ 1 ] < < 2 ) & 0xf0 ;
alpha = ( buf [ 1 ] < < 6 ) & 0xc0 ;
2005-12-17 20:14:38 +02:00
2005-07-17 03:28:12 +03:00
buf + = 2 ;
}
2005-12-17 20:14:38 +02:00
2005-07-17 03:28:12 +03:00
if ( y = = 0 )
alpha = 0xff ;
2005-12-17 20:14:38 +02:00
2005-07-17 03:28:12 +03:00
YUV_TO_RGB1_CCIR ( cb , cr ) ;
YUV_TO_RGB2_CCIR ( r , g , b , y ) ;
2005-12-17 20:14:38 +02:00
2015-03-16 10:57:36 +02:00
ff_dlog ( avctx , " clut %d := (%d,%d,%d,%d) \n " , entry_id , r , g , b , alpha ) ;
2013-09-18 20:55:40 +03:00
if ( ! ! ( depth & 0x80 ) + ! ! ( depth & 0x40 ) + ! ! ( depth & 0x20 ) > 1 ) {
2015-04-20 03:34:22 +02:00
ff_dlog ( avctx , " More than one bit level marked: %x \n " , depth ) ;
2013-09-18 20:55:40 +03:00
if ( avctx - > strict_std_compliance > FF_COMPLIANCE_NORMAL )
return AVERROR_INVALIDDATA ;
}
2005-12-17 20:14:38 +02:00
2017-05-11 15:18:50 +02:00
if ( depth & 0x80 & & entry_id < 4 )
2005-07-17 03:28:12 +03:00
clut - > clut4 [ entry_id ] = RGBA ( r , g , b , 255 - alpha ) ;
2017-05-11 15:18:50 +02:00
else if ( depth & 0x40 & & entry_id < 16 )
2005-07-17 03:28:12 +03:00
clut - > clut16 [ entry_id ] = RGBA ( r , g , b , 255 - alpha ) ;
2013-09-05 00:51:34 +03:00
else if ( depth & 0x20 )
2005-07-17 03:28:12 +03:00
clut - > clut256 [ entry_id ] = RGBA ( r , g , b , 255 - alpha ) ;
}
2011-10-14 17:41:21 +03:00
}
2014-12-17 17:02:09 +02:00
2013-09-18 20:55:40 +03:00
return 0 ;
2005-07-17 03:28:12 +03:00
}
2015-01-10 20:24:27 +02:00
static int dvbsub_parse_region_segment ( AVCodecContext * avctx ,
2014-12-17 17:02:09 +02:00
const uint8_t * buf , int buf_size )
2005-07-17 03:28:12 +03:00
{
2010-07-11 10:45:42 +03:00
DVBSubContext * ctx = avctx - > priv_data ;
2005-12-17 20:14:38 +02:00
2008-02-01 05:26:31 +02:00
const uint8_t * buf_end = buf + buf_size ;
2005-07-17 03:28:12 +03:00
int region_id , object_id ;
2012-03-30 20:59:48 +03:00
int av_unused version ;
2005-07-17 03:28:12 +03:00
DVBSubRegion * region ;
DVBSubObject * object ;
DVBSubObjectDisplay * display ;
int fill ;
2017-05-08 15:17:31 +02:00
int ret ;
2005-12-17 20:14:38 +02:00
2005-07-17 03:28:12 +03:00
if ( buf_size < 10 )
2015-01-10 20:24:27 +02:00
return AVERROR_INVALIDDATA ;
2005-12-17 20:14:38 +02:00
2005-07-17 03:28:12 +03:00
region_id = * buf + + ;
2005-12-17 20:14:38 +02:00
2005-07-17 03:28:12 +03:00
region = get_region ( ctx , region_id ) ;
2005-12-17 20:14:38 +02:00
2007-11-19 22:33:25 +02:00
if ( ! region ) {
2005-07-17 03:28:12 +03:00
region = av_mallocz ( sizeof ( DVBSubRegion ) ) ;
2015-01-10 20:18:59 +02:00
if ( ! region )
2015-01-10 20:24:27 +02:00
return AVERROR ( ENOMEM ) ;
2005-12-17 20:14:38 +02:00
2005-07-17 03:28:12 +03:00
region - > id = region_id ;
2011-10-14 17:41:21 +03:00
region - > version = - 1 ;
2005-12-17 20:14:38 +02:00
2005-07-17 03:28:12 +03:00
region - > next = ctx - > region_list ;
ctx - > region_list = region ;
}
2005-12-17 20:14:38 +02:00
2011-10-14 17:41:21 +03:00
version = ( ( * buf ) > > 4 ) & 15 ;
2005-07-17 03:28:12 +03:00
fill = ( ( * buf + + ) > > 3 ) & 1 ;
2005-12-17 20:14:38 +02:00
2007-01-20 00:12:59 +02:00
region - > width = AV_RB16 ( buf ) ;
2005-07-17 03:28:12 +03:00
buf + = 2 ;
2007-01-20 00:12:59 +02:00
region - > height = AV_RB16 ( buf ) ;
2005-07-17 03:28:12 +03:00
buf + = 2 ;
2005-12-17 20:14:38 +02:00
2017-06-09 23:04:30 +02:00
ret = av_image_check_size2 ( region - > width , region - > height , avctx - > max_pixels , AV_PIX_FMT_PAL8 , 0 , avctx ) ;
2017-06-09 23:16:55 +02:00
if ( ret > = 0 & & region - > width * region - > height * 2 > 320 * 1024 * 8 ) {
ret = AVERROR_INVALIDDATA ;
av_log ( avctx , AV_LOG_ERROR , " Pixel buffer memory constraint violated \n " ) ;
}
2017-05-08 15:17:31 +02:00
if ( ret < 0 ) {
region - > width = region - > height = 0 ;
return ret ;
}
2005-07-17 03:28:12 +03:00
if ( region - > width * region - > height ! = region - > buf_size ) {
2011-02-03 03:09:36 +02:00
av_free ( region - > pbuf ) ;
2005-12-17 20:14:38 +02:00
2005-07-17 03:28:12 +03:00
region - > buf_size = region - > width * region - > height ;
2005-12-17 20:14:38 +02:00
2005-07-17 03:28:12 +03:00
region - > pbuf = av_malloc ( region - > buf_size ) ;
2015-05-14 23:25:39 +02:00
if ( ! region - > pbuf ) {
region - > buf_size =
region - > width =
region - > height = 0 ;
2014-12-17 17:02:09 +02:00
return AVERROR ( ENOMEM ) ;
2015-05-14 23:25:39 +02:00
}
2005-12-17 20:14:38 +02:00
2005-07-17 03:28:12 +03:00
fill = 1 ;
2011-10-14 16:28:50 +03:00
region - > dirty = 0 ;
2005-07-17 03:28:12 +03:00
}
2005-12-17 20:14:38 +02:00
2005-07-17 03:28:12 +03:00
region - > depth = 1 < < ( ( ( * buf + + ) > > 2 ) & 7 ) ;
2007-11-19 22:14:46 +02:00
if ( region - > depth < 2 | | region - > depth > 8 ) {
av_log ( avctx , AV_LOG_ERROR , " region depth %d is invalid \n " , region - > depth ) ;
region - > depth = 4 ;
}
2005-07-17 03:28:12 +03:00
region - > clut = * buf + + ;
2005-12-17 20:14:38 +02:00
2011-10-14 17:08:06 +03:00
if ( region - > depth = = 8 ) {
2007-12-03 15:33:48 +02:00
region - > bgcolor = * buf + + ;
2011-10-14 17:08:06 +03:00
buf + = 1 ;
} else {
2005-07-17 03:28:12 +03:00
buf + = 1 ;
2005-12-17 20:14:38 +02:00
2005-07-17 03:28:12 +03:00
if ( region - > depth = = 4 )
2007-12-03 15:33:48 +02:00
region - > bgcolor = ( ( ( * buf + + ) > > 4 ) & 15 ) ;
2005-07-17 03:28:12 +03:00
else
2007-12-03 15:33:48 +02:00
region - > bgcolor = ( ( ( * buf + + ) > > 2 ) & 3 ) ;
2005-07-17 03:28:12 +03:00
}
2015-03-16 10:57:36 +02:00
ff_dlog ( avctx , " Region %d, (%dx%d) \n " , region_id , region - > width , region - > height ) ;
2005-07-17 03:28:12 +03:00
if ( fill ) {
2007-12-03 15:33:48 +02:00
memset ( region - > pbuf , region - > bgcolor , region - > buf_size ) ;
2015-03-16 10:57:36 +02:00
ff_dlog ( avctx , " Fill region (%d) \n " , region - > bgcolor ) ;
2005-07-17 03:28:12 +03:00
}
delete_region_display_list ( ctx , region ) ;
while ( buf + 5 < buf_end ) {
2007-01-20 00:12:59 +02:00
object_id = AV_RB16 ( buf ) ;
2005-07-17 03:28:12 +03:00
buf + = 2 ;
2005-12-17 20:14:38 +02:00
2005-07-17 03:28:12 +03:00
object = get_object ( ctx , object_id ) ;
2007-11-19 22:33:25 +02:00
if ( ! object ) {
2005-07-17 03:28:12 +03:00
object = av_mallocz ( sizeof ( DVBSubObject ) ) ;
2014-12-17 17:02:09 +02:00
if ( ! object )
return AVERROR ( ENOMEM ) ;
2005-12-17 20:14:38 +02:00
2005-07-17 03:28:12 +03:00
object - > id = object_id ;
object - > next = ctx - > object_list ;
ctx - > object_list = object ;
}
2005-12-17 20:14:38 +02:00
2005-07-17 03:28:12 +03:00
object - > type = ( * buf ) > > 6 ;
2005-12-17 20:14:38 +02:00
2005-07-17 03:28:12 +03:00
display = av_mallocz ( sizeof ( DVBSubObjectDisplay ) ) ;
2014-12-17 17:02:09 +02:00
if ( ! display )
return AVERROR ( ENOMEM ) ;
2005-12-17 20:14:38 +02:00
2005-07-17 03:28:12 +03:00
display - > object_id = object_id ;
display - > region_id = region_id ;
2005-12-17 20:14:38 +02:00
2007-01-20 00:12:59 +02:00
display - > x_pos = AV_RB16 ( buf ) & 0xfff ;
2005-07-17 03:28:12 +03:00
buf + = 2 ;
2007-01-20 00:12:59 +02:00
display - > y_pos = AV_RB16 ( buf ) & 0xfff ;
2005-07-17 03:28:12 +03:00
buf + = 2 ;
2005-12-17 20:14:38 +02:00
2005-07-17 03:28:12 +03:00
if ( ( object - > type = = 1 | | object - > type = = 2 ) & & buf + 1 < buf_end ) {
2007-12-03 15:33:48 +02:00
display - > fgcolor = * buf + + ;
display - > bgcolor = * buf + + ;
2005-07-17 03:28:12 +03:00
}
2005-12-17 20:14:38 +02:00
2005-07-17 03:28:12 +03:00
display - > region_list_next = region - > display_list ;
region - > display_list = display ;
2005-12-17 20:14:38 +02:00
2005-07-17 03:28:12 +03:00
display - > object_list_next = object - > display_list ;
object - > display_list = display ;
}
2015-01-10 20:24:27 +02:00
return 0 ;
2005-07-17 03:28:12 +03:00
}
2015-01-10 20:24:27 +02:00
static int dvbsub_parse_page_segment ( AVCodecContext * avctx ,
2015-01-27 21:25:40 +02:00
const uint8_t * buf , int buf_size , AVSubtitle * sub , int * got_output )
2005-07-17 03:28:12 +03:00
{
2010-07-11 10:45:42 +03:00
DVBSubContext * ctx = avctx - > priv_data ;
2005-07-17 03:28:12 +03:00
DVBSubRegionDisplay * display ;
DVBSubRegionDisplay * tmp_display_list , * * tmp_ptr ;
2005-12-17 20:14:38 +02:00
2008-02-01 05:26:31 +02:00
const uint8_t * buf_end = buf + buf_size ;
2005-07-17 03:28:12 +03:00
int region_id ;
int page_state ;
2011-10-14 17:41:21 +03:00
int timeout ;
int version ;
2005-12-17 20:14:38 +02:00
2005-07-17 03:28:12 +03:00
if ( buf_size < 1 )
2015-01-10 20:24:27 +02:00
return AVERROR_INVALIDDATA ;
2005-12-17 20:14:38 +02:00
2011-10-14 17:41:21 +03:00
timeout = * buf + + ;
version = ( ( * buf ) > > 4 ) & 15 ;
2005-07-17 03:28:12 +03:00
page_state = ( ( * buf + + ) > > 2 ) & 3 ;
2005-12-17 20:14:38 +02:00
2014-06-14 14:36:37 +03:00
if ( ctx - > version = = version ) {
2015-01-10 20:24:27 +02:00
return 0 ;
2014-06-14 14:36:37 +03:00
}
2011-10-14 17:41:21 +03:00
ctx - > time_out = timeout ;
ctx - > version = version ;
2015-03-16 10:57:36 +02:00
ff_dlog ( avctx , " Page time out %ds, state %d \n " , ctx - > time_out , page_state ) ;
2005-07-17 03:28:12 +03:00
2014-06-22 10:24:33 +03:00
if ( ctx - > compute_edt = = 1 )
save_subtitle_set ( avctx , sub , got_output ) ;
2011-10-14 17:33:34 +03:00
if ( page_state = = 1 | | page_state = = 2 ) {
2011-05-04 21:44:14 +03:00
delete_regions ( ctx ) ;
delete_objects ( ctx ) ;
delete_cluts ( ctx ) ;
2005-07-17 03:28:12 +03:00
}
2005-12-17 20:14:38 +02:00
2005-07-17 03:28:12 +03:00
tmp_display_list = ctx - > display_list ;
ctx - > display_list = NULL ;
2005-12-17 20:14:38 +02:00
2005-07-17 03:28:12 +03:00
while ( buf + 5 < buf_end ) {
region_id = * buf + + ;
buf + = 1 ;
2005-12-17 20:14:38 +02:00
2005-07-17 03:28:12 +03:00
display = tmp_display_list ;
tmp_ptr = & tmp_display_list ;
2005-12-17 20:14:38 +02:00
2007-11-19 22:26:35 +02:00
while ( display & & display - > region_id ! = region_id ) {
2005-07-17 03:28:12 +03:00
tmp_ptr = & display - > next ;
display = display - > next ;
}
2005-12-17 20:14:38 +02:00
2014-12-17 17:02:09 +02:00
if ( ! display ) {
2005-07-17 03:28:12 +03:00
display = av_mallocz ( sizeof ( DVBSubRegionDisplay ) ) ;
2014-12-17 17:02:09 +02:00
if ( ! display )
return AVERROR ( ENOMEM ) ;
}
2005-12-17 20:14:38 +02:00
2005-07-17 03:28:12 +03:00
display - > region_id = region_id ;
2005-12-17 20:14:38 +02:00
2007-01-20 00:12:59 +02:00
display - > x_pos = AV_RB16 ( buf ) ;
2005-07-17 03:28:12 +03:00
buf + = 2 ;
2007-01-20 00:12:59 +02:00
display - > y_pos = AV_RB16 ( buf ) ;
2005-07-17 03:28:12 +03:00
buf + = 2 ;
2005-12-17 20:14:38 +02:00
2005-07-17 03:28:12 +03:00
* tmp_ptr = display - > next ;
2005-12-17 20:14:38 +02:00
2005-07-17 03:28:12 +03:00
display - > next = ctx - > display_list ;
ctx - > display_list = display ;
2005-12-17 20:14:38 +02:00
2015-03-16 10:57:36 +02:00
ff_dlog ( avctx , " Region %d, (%d,%d) \n " , region_id , display - > x_pos , display - > y_pos ) ;
2005-07-17 03:28:12 +03:00
}
2005-12-17 20:14:38 +02:00
2007-11-19 22:26:35 +02:00
while ( tmp_display_list ) {
2005-07-17 03:28:12 +03:00
display = tmp_display_list ;
2005-12-17 20:14:38 +02:00
2005-07-17 03:28:12 +03:00
tmp_display_list = display - > next ;
2005-12-17 20:14:38 +02:00
2014-10-31 00:29:33 +02:00
av_freep ( & display ) ;
2005-07-17 03:28:12 +03:00
}
2005-12-17 20:14:38 +02:00
2015-01-10 20:24:27 +02:00
return 0 ;
2005-07-17 03:28:12 +03:00
}
2011-06-06 01:53:31 +03:00
# ifdef DEBUG
2017-04-03 22:18:14 +02:00
static void png_save ( DVBSubContext * ctx , const char * filename , uint32_t * bitmap , int w , int h )
2015-12-11 21:17:31 +02:00
{
int x , y , v ;
FILE * f ;
char fname [ 40 ] , fname2 [ 40 ] ;
char command [ 1024 ] ;
snprintf ( fname , sizeof ( fname ) , " %s.ppm " , filename ) ;
f = fopen ( fname , " w " ) ;
if ( ! f ) {
perror ( fname ) ;
return ;
}
fprintf ( f , " P6 \n "
" %d %d \n "
" %d \n " ,
w , h , 255 ) ;
for ( y = 0 ; y < h ; y + + ) {
for ( x = 0 ; x < w ; x + + ) {
v = bitmap [ y * w + x ] ;
putc ( ( v > > 16 ) & 0xff , f ) ;
putc ( ( v > > 8 ) & 0xff , f ) ;
putc ( ( v > > 0 ) & 0xff , f ) ;
}
}
fclose ( f ) ;
snprintf ( fname2 , sizeof ( fname2 ) , " %s-a.pgm " , filename ) ;
f = fopen ( fname2 , " w " ) ;
if ( ! f ) {
perror ( fname2 ) ;
return ;
}
fprintf ( f , " P5 \n "
" %d %d \n "
" %d \n " ,
w , h , 255 ) ;
for ( y = 0 ; y < h ; y + + ) {
for ( x = 0 ; x < w ; x + + ) {
v = bitmap [ y * w + x ] ;
putc ( ( v > > 24 ) & 0xff , f ) ;
}
}
fclose ( f ) ;
snprintf ( command , sizeof ( command ) , " pnmtopng -alpha %s %s > %s.png 2> /dev/null " , fname2 , fname , filename ) ;
if ( system ( command ) ! = 0 ) {
2017-04-03 22:18:14 +02:00
av_log ( ctx , AV_LOG_ERROR , " Error running pnmtopng \n " ) ;
2015-12-11 21:17:31 +02:00
return ;
}
snprintf ( command , sizeof ( command ) , " rm %s %s " , fname , fname2 ) ;
if ( system ( command ) ! = 0 ) {
2017-04-03 22:18:14 +02:00
av_log ( ctx , AV_LOG_ERROR , " Error removing %s and %s \n " , fname , fname2 ) ;
2015-12-11 21:17:31 +02:00
return ;
}
}
2015-10-02 12:43:40 +02:00
static int save_display_set ( DVBSubContext * ctx )
2005-07-17 03:28:12 +03:00
{
DVBSubRegion * region ;
DVBSubRegionDisplay * display ;
DVBSubCLUT * clut ;
uint32_t * clut_table ;
int x_pos , y_pos , width , height ;
int x , y , y_off , x_off ;
uint32_t * pbuf ;
char filename [ 32 ] ;
static int fileno_index = 0 ;
x_pos = - 1 ;
y_pos = - 1 ;
width = 0 ;
height = 0 ;
2005-12-17 20:14:38 +02:00
2007-11-19 22:26:35 +02:00
for ( display = ctx - > display_list ; display ; display = display - > next ) {
2005-07-17 03:28:12 +03:00
region = get_region ( ctx , display - > region_id ) ;
2005-12-17 20:14:38 +02:00
2015-01-17 17:21:36 +02:00
if ( ! region )
2015-10-05 11:24:10 +02:00
return - 1 ;
2015-01-17 17:21:36 +02:00
2005-07-17 03:28:12 +03:00
if ( x_pos = = - 1 ) {
x_pos = display - > x_pos ;
y_pos = display - > y_pos ;
width = region - > width ;
height = region - > height ;
} else {
if ( display - > x_pos < x_pos ) {
width + = ( x_pos - display - > x_pos ) ;
x_pos = display - > x_pos ;
}
2005-12-17 20:14:38 +02:00
2005-07-17 03:28:12 +03:00
if ( display - > y_pos < y_pos ) {
height + = ( y_pos - display - > y_pos ) ;
y_pos = display - > y_pos ;
}
2005-12-17 20:14:38 +02:00
2005-07-17 03:28:12 +03:00
if ( display - > x_pos + region - > width > x_pos + width ) {
width = display - > x_pos + region - > width - x_pos ;
}
2005-12-17 20:14:38 +02:00
2005-07-17 03:28:12 +03:00
if ( display - > y_pos + region - > height > y_pos + height ) {
height = display - > y_pos + region - > height - y_pos ;
}
}
}
2005-12-17 20:14:38 +02:00
2005-07-17 03:28:12 +03:00
if ( x_pos > = 0 ) {
2005-12-17 20:14:38 +02:00
2005-07-17 03:28:12 +03:00
pbuf = av_malloc ( width * height * 4 ) ;
2014-12-17 17:02:09 +02:00
if ( ! pbuf )
2015-10-05 11:24:10 +02:00
return - 1 ;
2005-07-17 03:28:12 +03:00
2007-11-19 22:26:35 +02:00
for ( display = ctx - > display_list ; display ; display = display - > next ) {
2005-07-17 03:28:12 +03:00
region = get_region ( ctx , display - > region_id ) ;
2015-01-17 17:21:36 +02:00
if ( ! region )
2015-10-05 11:24:10 +02:00
return - 1 ;
2015-01-17 17:21:36 +02:00
2005-07-17 03:28:12 +03:00
x_off = display - > x_pos - x_pos ;
y_off = display - > y_pos - y_pos ;
clut = get_clut ( ctx , region - > clut ) ;
2014-08-16 01:41:07 +03:00
if ( ! clut )
2005-07-17 03:28:12 +03:00
clut = & default_clut ;
switch ( region - > depth ) {
case 2 :
clut_table = clut - > clut4 ;
break ;
case 8 :
clut_table = clut - > clut256 ;
break ;
case 4 :
default :
clut_table = clut - > clut16 ;
break ;
}
2005-12-17 20:14:38 +02:00
2005-07-17 03:28:12 +03:00
for ( y = 0 ; y < region - > height ; y + + ) {
for ( x = 0 ; x < region - > width ; x + + ) {
2005-12-17 20:14:38 +02:00
pbuf [ ( ( y + y_off ) * width ) + x_off + x ] =
2005-07-17 03:28:12 +03:00
clut_table [ region - > pbuf [ y * region - > width + x ] ] ;
}
}
2005-12-17 20:14:38 +02:00
}
2005-07-17 03:28:12 +03:00
2007-11-19 22:18:30 +02:00
snprintf ( filename , sizeof ( filename ) , " dvbs.%d " , fileno_index ) ;
2005-07-17 03:28:12 +03:00
2017-04-03 22:18:14 +02:00
png_save ( ctx , filename , pbuf , width , height ) ;
2005-07-17 03:28:12 +03:00
2014-10-31 00:29:33 +02:00
av_freep ( & pbuf ) ;
2005-07-17 03:28:12 +03:00
}
2005-12-17 20:14:38 +02:00
2005-07-17 03:28:12 +03:00
fileno_index + + ;
2015-10-02 12:43:40 +02:00
return 0 ;
2005-07-17 03:28:12 +03:00
}
2015-12-11 21:17:31 +02:00
# endif /* DEBUG */
2005-07-17 03:28:12 +03:00
2015-01-10 20:24:27 +02:00
static int dvbsub_parse_display_definition_segment ( AVCodecContext * avctx ,
2014-12-17 17:02:09 +02:00
const uint8_t * buf ,
int buf_size )
2010-06-16 16:07:12 +03:00
{
DVBSubContext * ctx = avctx - > priv_data ;
DVBSubDisplayDefinition * display_def = ctx - > display_definition ;
int dds_version , info_byte ;
if ( buf_size < 5 )
2015-01-10 20:24:27 +02:00
return AVERROR_INVALIDDATA ;
2010-06-16 16:07:12 +03:00
info_byte = bytestream_get_byte ( & buf ) ;
dds_version = info_byte > > 4 ;
if ( display_def & & display_def - > version = = dds_version )
2015-01-10 20:24:27 +02:00
return 0 ; // already have this display definition version
2010-06-16 16:07:12 +03:00
if ( ! display_def ) {
display_def = av_mallocz ( sizeof ( * display_def ) ) ;
2014-12-17 17:02:09 +02:00
if ( ! display_def )
return AVERROR ( ENOMEM ) ;
2010-06-16 16:07:12 +03:00
ctx - > display_definition = display_def ;
}
display_def - > version = dds_version ;
display_def - > x = 0 ;
display_def - > y = 0 ;
display_def - > width = bytestream_get_be16 ( & buf ) + 1 ;
display_def - > height = bytestream_get_be16 ( & buf ) + 1 ;
2012-08-27 18:57:11 +03:00
if ( ! avctx - > width | | ! avctx - > height ) {
avctx - > width = display_def - > width ;
avctx - > height = display_def - > height ;
}
2010-06-16 16:07:12 +03:00
if ( info_byte & 1 < < 3 ) { // display_window_flag
2015-05-30 04:28:39 +02:00
if ( buf_size < 13 )
return AVERROR_INVALIDDATA ;
2010-06-16 16:07:12 +03:00
display_def - > x = bytestream_get_be16 ( & buf ) ;
display_def - > width = bytestream_get_be16 ( & buf ) - display_def - > x + 1 ;
2013-12-13 16:29:09 +03:00
display_def - > y = bytestream_get_be16 ( & buf ) ;
2010-06-16 16:07:12 +03:00
display_def - > height = bytestream_get_be16 ( & buf ) - display_def - > y + 1 ;
}
2015-01-10 20:24:27 +02:00
return 0 ;
2010-06-16 16:07:12 +03:00
}
2008-02-01 05:26:31 +02:00
static int dvbsub_display_end_segment ( AVCodecContext * avctx , const uint8_t * buf ,
2015-01-27 21:25:40 +02:00
int buf_size , AVSubtitle * sub , int * got_output )
2005-07-17 03:28:12 +03:00
{
2010-07-11 10:45:42 +03:00
DVBSubContext * ctx = avctx - > priv_data ;
2005-07-17 03:28:12 +03:00
2014-06-22 10:24:33 +03:00
if ( ctx - > compute_edt = = 0 )
save_subtitle_set ( avctx , sub , got_output ) ;
2011-06-06 01:53:31 +03:00
# ifdef DEBUG
2005-07-17 03:28:12 +03:00
save_display_set ( ctx ) ;
# endif
2015-01-27 21:25:40 +02:00
return 0 ;
2005-07-17 03:28:12 +03:00
}
static int dvbsub_decode ( AVCodecContext * avctx ,
void * data , int * data_size ,
2009-04-07 18:59:50 +03:00
AVPacket * avpkt )
2005-07-17 03:28:12 +03:00
{
2009-04-07 18:59:50 +03:00
const uint8_t * buf = avpkt - > data ;
int buf_size = avpkt - > size ;
2010-07-11 10:45:42 +03:00
DVBSubContext * ctx = avctx - > priv_data ;
AVSubtitle * sub = data ;
2008-02-01 05:26:31 +02:00
const uint8_t * p , * p_end ;
2005-07-17 03:28:12 +03:00
int segment_type ;
int page_id ;
int segment_length ;
int i ;
2014-06-22 10:24:33 +03:00
int ret = 0 ;
2012-01-29 16:50:19 +03:00
int got_segment = 0 ;
2015-07-29 17:59:51 +02:00
int got_dds = 0 ;
2005-07-17 03:28:12 +03:00
2015-03-16 10:57:36 +02:00
ff_dlog ( avctx , " DVB sub packet: \n " ) ;
2005-07-17 03:28:12 +03:00
2007-11-19 22:30:00 +02:00
for ( i = 0 ; i < buf_size ; i + + ) {
2015-03-16 10:57:36 +02:00
ff_dlog ( avctx , " %02x " , buf [ i ] ) ;
2005-07-17 03:28:12 +03:00
if ( i % 16 = = 15 )
2015-03-16 10:57:36 +02:00
ff_dlog ( avctx , " \n " ) ;
2005-07-17 03:28:12 +03:00
}
2005-12-17 20:14:38 +02:00
2007-11-19 22:26:35 +02:00
if ( i % 16 )
2015-03-16 10:57:36 +02:00
ff_dlog ( avctx , " \n " ) ;
2005-07-17 03:28:12 +03:00
2011-02-10 00:23:22 +02:00
if ( buf_size < = 6 | | * buf ! = 0x0f ) {
2015-03-16 10:57:36 +02:00
ff_dlog ( avctx , " incomplete or broken packet " ) ;
2014-12-17 17:02:09 +02:00
return AVERROR_INVALIDDATA ;
2011-02-10 00:23:22 +02:00
}
2005-12-17 20:14:38 +02:00
2005-07-17 03:28:12 +03:00
p = buf ;
p_end = buf + buf_size ;
2005-12-17 20:14:38 +02:00
2011-02-10 00:23:22 +02:00
while ( p_end - p > = 6 & & * p = = 0x0f ) {
2005-07-17 03:28:12 +03:00
p + = 1 ;
segment_type = * p + + ;
2007-01-20 00:12:59 +02:00
page_id = AV_RB16 ( p ) ;
2005-07-17 03:28:12 +03:00
p + = 2 ;
2007-01-20 00:12:59 +02:00
segment_length = AV_RB16 ( p ) ;
2005-07-17 03:28:12 +03:00
p + = 2 ;
2005-12-17 20:14:38 +02:00
2014-06-04 19:09:18 +03:00
if ( avctx - > debug & FF_DEBUG_STARTCODE ) {
av_log ( avctx , AV_LOG_DEBUG , " segment_type:%d page_id:%d segment_length:%d \n " , segment_type , page_id , segment_length ) ;
}
2011-02-10 00:23:22 +02:00
if ( p_end - p < segment_length ) {
2015-03-16 10:57:36 +02:00
ff_dlog ( avctx , " incomplete or broken packet " ) ;
2014-06-22 10:24:33 +03:00
ret = - 1 ;
goto end ;
2011-02-10 00:23:22 +02:00
}
2010-07-14 20:28:40 +03:00
if ( page_id = = ctx - > composition_id | | page_id = = ctx - > ancillary_id | |
ctx - > composition_id = = - 1 | | ctx - > ancillary_id = = - 1 ) {
2014-12-17 17:02:09 +02:00
int ret = 0 ;
2005-07-17 03:28:12 +03:00
switch ( segment_type ) {
case DVBSUB_PAGE_SEGMENT :
2015-01-27 21:25:40 +02:00
ret = dvbsub_parse_page_segment ( avctx , p , segment_length , sub , data_size ) ;
2012-01-29 16:50:19 +03:00
got_segment | = 1 ;
2005-07-17 03:28:12 +03:00
break ;
case DVBSUB_REGION_SEGMENT :
2014-12-17 17:02:09 +02:00
ret = dvbsub_parse_region_segment ( avctx , p , segment_length ) ;
2012-01-29 16:50:19 +03:00
got_segment | = 2 ;
2005-07-17 03:28:12 +03:00
break ;
case DVBSUB_CLUT_SEGMENT :
2013-09-18 20:55:40 +03:00
ret = dvbsub_parse_clut_segment ( avctx , p , segment_length ) ;
2014-06-22 10:24:33 +03:00
if ( ret < 0 ) goto end ;
2012-01-29 16:50:19 +03:00
got_segment | = 4 ;
2005-07-17 03:28:12 +03:00
break ;
case DVBSUB_OBJECT_SEGMENT :
2014-12-17 17:02:09 +02:00
ret = dvbsub_parse_object_segment ( avctx , p , segment_length ) ;
2012-01-29 16:50:19 +03:00
got_segment | = 8 ;
2005-07-17 03:28:12 +03:00
break ;
2010-06-16 16:07:12 +03:00
case DVBSUB_DISPLAYDEFINITION_SEGMENT :
2014-12-17 17:02:09 +02:00
ret = dvbsub_parse_display_definition_segment ( avctx , p ,
segment_length ) ;
2015-07-29 17:59:51 +02:00
got_dds = 1 ;
2011-07-11 11:11:04 +03:00
break ;
2005-07-17 03:28:12 +03:00
case DVBSUB_DISPLAY_SEGMENT :
2015-01-27 21:25:40 +02:00
ret = dvbsub_display_end_segment ( avctx , p , segment_length , sub , data_size ) ;
2015-07-29 17:59:51 +02:00
if ( got_segment = = 15 & & ! got_dds & & ! avctx - > width & & ! avctx - > height ) {
// Default from ETSI EN 300 743 V1.3.1 (7.2.1)
avctx - > width = 720 ;
avctx - > height = 576 ;
}
2012-01-29 16:50:19 +03:00
got_segment | = 16 ;
2005-07-17 03:28:12 +03:00
break ;
default :
2015-03-16 10:57:36 +02:00
ff_dlog ( avctx , " Subtitling segment type 0x%x, page id %d, length %d \n " ,
2005-07-17 03:28:12 +03:00
segment_type , page_id , segment_length ) ;
break ;
}
2014-12-17 17:02:09 +02:00
if ( ret < 0 )
2015-01-27 21:25:40 +02:00
goto end ;
2005-07-17 03:28:12 +03:00
}
p + = segment_length ;
}
2012-01-29 16:50:19 +03:00
// Some streams do not send a display segment but if we have all the other
// segments then we need no further data.
2014-07-02 19:21:37 +03:00
if ( got_segment = = 15 ) {
2014-06-04 19:09:18 +03:00
av_log ( avctx , AV_LOG_DEBUG , " Missing display_end_segment, emulating \n " ) ;
2014-06-22 10:24:33 +03:00
dvbsub_display_end_segment ( avctx , p , 0 , sub , data_size ) ;
}
end :
if ( ret < 0 ) {
* data_size = 0 ;
avsubtitle_free ( sub ) ;
return ret ;
} else {
if ( ctx - > compute_edt = = 1 )
FFSWAP ( int64_t , ctx - > prev_start , sub - > pts ) ;
2014-06-04 19:09:18 +03:00
}
2005-12-17 20:14:38 +02:00
2011-02-09 20:32:07 +02:00
return p - buf ;
2005-07-17 03:28:12 +03:00
}
2014-09-01 05:13:48 +03:00
# define DS AV_OPT_FLAG_DECODING_PARAM | AV_OPT_FLAG_SUBTITLE_PARAM
2014-06-14 14:36:37 +03:00
static const AVOption options [ ] = {
2015-11-21 23:04:39 +02:00
{ " compute_edt " , " compute end of time using pts or timeout " , offsetof ( DVBSubContext , compute_edt ) , AV_OPT_TYPE_BOOL , { . i64 = 0 } , 0 , 1 , DS } ,
{ " compute_clut " , " compute clut when not available(-1) or always(1) or never(0) " , offsetof ( DVBSubContext , compute_clut ) , AV_OPT_TYPE_BOOL , { . i64 = - 1 } , - 1 , 1 , DS } ,
2015-08-17 01:34:13 +02:00
{ " dvb_substream " , " " , offsetof ( DVBSubContext , substream ) , AV_OPT_TYPE_INT , { . i64 = - 1 } , - 1 , 63 , DS } ,
2014-06-14 14:36:37 +03:00
{ NULL }
} ;
static const AVClass dvbsubdec_class = {
. class_name = " DVB Sub Decoder " ,
. item_name = av_default_item_name ,
. option = options ,
. version = LIBAVUTIL_VERSION_INT ,
} ;
2005-07-17 03:28:12 +03:00
2011-01-25 23:40:11 +02:00
AVCodec ff_dvbsub_decoder = {
2011-07-17 13:54:31 +03:00
. name = " dvbsub " ,
2013-10-03 23:57:53 +03:00
. long_name = NULL_IF_CONFIG_SMALL ( " DVB subtitles " ) ,
2011-07-17 13:54:31 +03:00
. type = AVMEDIA_TYPE_SUBTITLE ,
2012-08-05 12:11:04 +03:00
. id = AV_CODEC_ID_DVB_SUBTITLE ,
2011-07-17 13:54:31 +03:00
. priv_data_size = sizeof ( DVBSubContext ) ,
. init = dvbsub_init_decoder ,
. close = dvbsub_close_decoder ,
. decode = dvbsub_decode ,
2014-06-14 14:36:37 +03:00
. priv_class = & dvbsubdec_class ,
2005-07-17 03:28:12 +03:00
} ;