Implementation of DVB Subtitle

This commit is contained in:
Anshul Maheshwari 2014-04-29 16:29:19 +05:30
parent 6033e5bea8
commit a6c36197ba
11 changed files with 1874 additions and 16 deletions

3
.gitignore vendored
View File

@ -1,3 +1,6 @@
#Ignore CVS
.CVS
CVS
*.o
linux/ccextractor
linux/depend

View File

@ -19,7 +19,7 @@ src_OBJS = \
encoding.o es_functions.o es_userdata.o file_functions.o \
general_loop.o mp4.o myth.o output.o params_dump.o params.o \
sequencing.o stream_functions.o telxcc.o timing.o ts_functions.o \
utility.o wtv_functions.o xds.o
utility.o wtv_functions.o xds.o dvb_subtitle_decoder.o ts_tables.o
gpacmp4_OBJS = \
avc_ext.o avilib.o av_parsers.o base_encoding.o bitstream.o \
@ -42,7 +42,8 @@ src_SRC = \
../src/output.cpp ../src/params.cpp ../src/params_dump.cpp \
../src/sequencing.cpp ../src/stream_functions.cpp ../src/telxcc.cpp \
../src/timing.cpp ../src/ts_functions.cpp ../src/utility.cpp \
../src/wtv_functions.cpp ../src/xds.cpp
../src/wtv_functions.cpp ../src/xds.cpp ../src/dvb_subtitle_decoder.c \
../src/ts_tables.cpp
gpacmp4_SRC = \
../src/gpacmp4/avc_ext.c ../src/gpacmp4/avilib.c \

View File

@ -104,6 +104,11 @@ void init_options (struct ccx_s_options *options)
options->direct_rollup=0; // Write roll-up captions directly instead of line by line?
options->nofontcolor=0; // 1 = don't put <font color> tags
options->notypesetting=0; // 1 = Don't put <i>, <u>, etc typesetting tags
/* Select subtitle codec */
options->codec = CCX_CODEC_ANY;
options->nocodec = CCX_CODEC_NONE;
/* Credit stuff */
options->start_credits_text=NULL;
options->end_credits_text=NULL;

View File

@ -42,6 +42,10 @@ struct ccx_s_options // Options from user parameters
int nofontcolor;
int notypesetting;
struct ccx_boundary_time extraction_start, extraction_end; // Segment we actually process
/* subtitle codec type */
enum cxx_code_type codec;
enum cxx_code_type nocodec;
/* Credit stuff */
char *start_credits_text;
char *end_credits_text;

View File

@ -123,6 +123,7 @@ enum ccx_mpeg_descriptor
CCX_MPEG_DSC_VBI_DATA_DESCRIPTOR = 0x45,
CCX_MPEG_DSC_VBI_TELETEXT_DESCRIPTOR = 0x46,
CCX_MPEG_DSC_TELETEXT_DESCRIPTOR = 0x56,
CCX_MPEG_DSC_DVB_SUBTITLE = 0x59,
};
enum
@ -191,7 +192,8 @@ enum ccx_bufferdata_type
CCX_H264 = 3,
CCX_HAUPPAGE = 4,
CCX_TELETEXT = 5,
CCX_PRIVATE_MPEG2_CC = 6
CCX_PRIVATE_MPEG2_CC = 6,
CCX_DVB_SUBTITLE = 7,
};
enum ccx_frame_type
@ -209,6 +211,32 @@ typedef enum {
UNDEF = 0xff
} bool_t;
enum cxx_code_type
{
CCX_CODEC_ANY,
CCX_CODEC_TELETEXT,
CCX_CODEC_DVB,
CCX_CODEC_NONE,
};
/*
* This macro to be used when you want to find out whether you
* should parse f_sel subtitle codec type or not
*
* @param u_sel pass the codec selected by user to be searched in
* all elementry stream, we ignore the not to be selected stream
* if we find stream this is selected stream. since setting
* selected stream and not selected to same codec does not
* make ay sense.
*
* @param u_nsel pass the codec selected by user not to be parsed
* we give false value if f_sel is equal to n_sel
* and vice versa true if ...
*
* @param f_sel pass the codec name whom you are tesing to be feasible
* to parse.
*/
#define IS_FEASIBLE(u_sel,u_nsel,f_sel) ( ( (u_sel) == CCX_CODEC_ANY && (u_nsel) != (f_sel) ) || (u_sel) == (f_sel) )
#define CCX_TXT_FORBIDDEN 0 // Ignore teletext packets
#define CCX_TXT_AUTO_NOT_YET_FOUND 1
#define CCX_TXT_IN_USE 2 // Positive autodetected, or forced, etc

1643
src/dvb_subtitle_decoder.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,74 @@
/*
* DVB subtitle decoding
* Copyright (c) 2014 Anshul
* License: LGPL
*
* This file is part of CCEXtractor
* You should have received a copy of the GNU Lesser General Public
* License along with CCExtractor; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
/**
* @file dvbsub.c
*/
#ifndef DVBSUBDEC_H
#define DVBSUBDEC_H
#define MAX_LANGUAGE_PER_DESC 5
struct dvb_config
{
unsigned char n_language;
unsigned int lang_index[MAX_LANGUAGE_PER_DESC];
/* subtitle type */
unsigned char sub_type[MAX_LANGUAGE_PER_DESC];
/* composition page id */
unsigned short composition_id[MAX_LANGUAGE_PER_DESC];
/* ancillary_page_id */
unsigned short ancillary_id[MAX_LANGUAGE_PER_DESC];
};
/**
* @param composition_id composition-page_id found in Subtitle descriptors
* associated with subtitle stream in the PMT
* it could be -1 if not found in PMT.
* @param ancillary_id ancillary-page_id found in Subtitle descriptors
* associated with subtitle stream in the PMT.
* it could be -1 if not found in PMT.
*
* @return DVB context kept as void* for abstraction
*
*/
void* dvbsub_init_decoder(int composition_id,int ancillary_id);
int dvbsub_close_decoder(void *dvb_ctx);
/**
* @param dvb_ctx PreInitialized DVB context using DVB
* @param data output subtitle data, to be implemented
* @param data_size Output subtitle data size. pass the pointer to an intiger, NOT to be NULL.
* @param buf buffer containg segment data, first sync byte needto 0x0f.
* does not include data_identifier and subtitle_stream_id.
* @param buf_size size of buf buffer
*
* @return -1 on error
*/
int dvbsub_decode(void *dvb_ctx,
void *data, int *data_size,
const unsigned char *buf,int buf_size);
/**
* @func parse_dvb_description
*
* data pointer to this function should be after description length and description tag is parsed
*
* @param cfg preallocated dvb_config structure where parsed description will be stored,Not to be NULL
*
* @return return -1 if invalid data found other wise 0 if everything goes well
* errno is set is to EINVAL if invalid data is found
*/
int parse_dvb_description (struct dvb_config* cfg,unsigned char*data,unsigned int len);
#endif

View File

@ -6,6 +6,7 @@
#endif
#include "708.h"
#include "dvb_subtitle_decoder.h"
// IMPORTED TRASH INFO, REMOVE
extern long num_nal_unit_type_7;
@ -43,10 +44,10 @@ unsigned char *filebuffer;
LLONG filebuffer_start; // Position of buffer start relative to file
int filebuffer_pos; // Position of pointer relative to buffer start
int bytesinbuffer; // Number of bytes we actually have on buffer
extern void *cxx_dvb_context;
LLONG process_raw_with_field (void);
// Program stream specific data grabber
LLONG ps_getmoredata(void)
{
@ -598,6 +599,12 @@ void general_loop(void)
if (pts_set)
set_fts(); // Try to fix timing from TS data
}
else if(ccx_bufferdatatype == CCX_DVB_SUBTITLE)
{
int out_size = 0;
dvbsub_decode(cxx_dvb_context,NULL,&out_size,buffer + 2,inbuf);
got = inbuf;
}
else if (ccx_bufferdatatype == CCX_PES)
{
got = process_m2v (buffer, inbuf);

View File

@ -560,6 +560,7 @@ void usage (void)
mprint ("generate a .srt file, with only data from 3:00 to 5:00 in the input file(s)\n");
mprint ("and then add that (huge) delay, which would make the final file start at\n");
mprint ("5:00 and end at 7:00.\n\n");
mprint ("Options that affect what segment of the input file(s) to process:\n");
mprint (" -startat time: Only write caption information that starts after the\n");
mprint (" given time.\n");
@ -572,6 +573,24 @@ void usage (void)
mprint (" output formats. In all formats with timing information\n");
mprint (" the times are unchanged.\n");
mprint ("-scr --screenfuls num: Write 'num' screenfuls and terminate processing.\n\n");
mprint ("Options that affect which codec is to be used have to be searched in input\n");
mprint (" If codec type is not selected then first elementry stream suitable for \n"
" subtitle is selected, please consider -teletext -noteletext override this\n"
" option.\n"
" -cocdec dvbsub select the dvb subtitle from all elementry stream,\n"
" if stream of dvb subtitle type is not found then \n"
" nothing is selected and no subtitle is generated\n"
" -nocodec dvbsub ignore dvb subtitle and follow default behaviour\n"
" -codec teletext select the teletext subtitle from elementry stream\n"
" -nocodec teletext ignore teletext subtitle\n"
" NOTE: option given in form -foo=bar ,-foo = bar and --foo=bar are invalid\n"
" valid option are only in form -foo bar\n"
" nocodec and codec parameter must not be same if found to be same \n"
" then parameter of nocodec is ignored, this flag should be passed \n"
" once more then one are not supported yet and last parameter would \n"
" taken in consideration\n");
mprint ("Adding start and end credits:\n");
mprint (" CCExtractor can _try_ to add a custom message (for credits for example) at\n");
mprint (" the start and end of the file, looking for a window where there are no\n");
@ -818,6 +837,45 @@ void parse_parameters (int argc, char *argv[])
set_input_format (argv[i]+4);
continue;
}
/*user specified subtitle to be selected */
if(!strcmp (argv[i],"-codec"))
{
i++;
if(!strcmp (argv[i],"teletext"))
{
ccx_options.codec = CCX_CODEC_TELETEXT;
}
else if(!strcmp (argv[i],"dvbsub"))
{
ccx_options.codec = CCX_CODEC_DVB;
}
else
{
mprint("Invalid option for codec %s\n",argv[i]);
}
continue;
}
/*user specified subtitle to be selected */
if(!strcmp (argv[i],"-nocodec"))
{
i++;
if(!strcmp (argv[i],"teletext"))
{
ccx_options.nocodec = CCX_CODEC_TELETEXT;
}
else if(!strcmp (argv[i],"dvbsub"))
{
ccx_options.nocodec = CCX_CODEC_DVB;
}
else
{
mprint("Invalid option for codec %s\n",argv[i]);
}
continue;
}
/* Output file formats */
if (strcmp (argv[i],"-srt")==0 ||
strcmp (argv[i],"-dvdraw")==0 ||
@ -1367,11 +1425,13 @@ void parse_parameters (int argc, char *argv[])
}
if (strcmp (argv[i],"-teletext")==0)
{
ccx_options.codec = CCX_CODEC_TELETEXT;
ccx_options.teletext_mode=CCX_TXT_IN_USE;
continue;
}
if (strcmp (argv[i],"-noteletext")==0)
{
ccx_options.nocodec = CCX_CODEC_TELETEXT;
ccx_options.teletext_mode=CCX_TXT_FORBIDDEN;
continue;
}

View File

@ -17,7 +17,7 @@ static long haup_capbuflen = 0; // Bytes read in haup_capbuf
unsigned TS_program_number = 0; // Identifier for current program
unsigned pmtpid = 0; // PID for Program Map Table
unsigned cap_stream_type=CCX_STREAM_TYPE_UNKNOWNSTREAM; // Stream type for cappid
extern void *cxx_dvb_context;
// Descriptions for ts ccx_stream_type
const char *desc[256];
@ -464,6 +464,11 @@ LLONG ts_getmoredata(void)
ccx_bufferdatatype = CCX_H264;
tstr = "H.264";
}
else if ( cap_stream_type == CCX_STREAM_TYPE_PRIVATE_MPEG2 && cxx_dvb_context )
{
ccx_bufferdatatype = CCX_DVB_SUBTITLE;
tstr = "DVB subtitle";
}
else if ( cap_stream_type == CCX_STREAM_TYPE_UNKNOWNSTREAM && ccx_options.hauppauge_mode)
{
ccx_bufferdatatype = CCX_HAUPPAGE;
@ -566,13 +571,6 @@ LLONG ts_getmoredata(void)
haup_capbuflen=0;
}
if( !((stream_id&0xf0)==0xe0)) // 0xBD = private stream
{
// ??? Shouldn't happen. Complain and try again.
mprint("Not a video PES header!\n");
continue;
}
dbg_print(CCX_DMT_VERBOSE, "TS payload start video PES id: %d len: %ld\n",
stream_id, capbuflen);

View File

@ -6,8 +6,10 @@
*/
#include "ccextractor.h"
#include "dvb_subtitle_decoder.h"
static unsigned pmt_warning_shown=0; // Only display warning once
void *cxx_dvb_context = NULL;
// PMTs table
PAT_entry pmt_array[TS_PMT_MAP_SIZE] = { 0 };
@ -64,6 +66,8 @@ void clear_PMT_array (void)
int parse_PMT (int pos)
{
int must_flush=0;
int ret = 0;
unsigned char desc_len = 0;
if ((ccx_options.ts_forced_cappid || (ccx_options.teletext_mode==CCX_TXT_IN_USE && ccx_options.ts_cappid)) &&
cap_stream_type!=CCX_STREAM_TYPE_UNKNOWNSTREAM) // Already know what we need, skip
@ -190,20 +194,47 @@ int parse_PMT (int pos)
for( unsigned i=0; i < stream_data && (i+4)<payload_length; i+=5)
{
unsigned ccx_stream_type = payload_start[i];
unsigned elementary_PID = (((payload_start[i+1] & 0x1F) << 8)
unsigned ccx_stream_type = payload_start[i];
unsigned elementary_PID = (((payload_start[i+1] & 0x1F) << 8)
| payload_start[i+2]);
unsigned ES_info_length = (((payload_start[i+3] & 0x0F) << 8)
unsigned ES_info_length = (((payload_start[i+3] & 0x0F) << 8)
| payload_start[i+4]);
/* There is no information about elementry stream */
if(!ES_info_length)
continue;
if (ccx_options.ts_cappid==0 && ccx_stream_type==ccx_options.ts_datastreamtype) // Found a stream with the type the user wants
{
ccx_options.ts_forced_cappid=1;
ccx_options.ts_cappid = newcappid = elementary_PID;
cap_stream_type=CCX_STREAM_TYPE_UNKNOWNSTREAM;
}
if(IS_FEASIBLE(ccx_options.codec,ccx_options.nocodec,CCX_CODEC_DVB) && !ccx_options.ts_cappid && ccx_stream_type == CCX_STREAM_TYPE_PRIVATE_MPEG2)
{
unsigned char *es_info = payload_start + i + 5;
for (desc_len = 0;(payload_start + i + 5 + ES_info_length) - es_info ;es_info += desc_len)
{
enum ccx_mpeg_descriptor descriptor_tag = (enum ccx_mpeg_descriptor)(*es_info++);
desc_len = (*es_info++);
if(CCX_MPEG_DSC_DVB_SUBTITLE == descriptor_tag)
{
struct dvb_config cnf;
memset((void*)&cnf,0,sizeof(struct dvb_config));
ret = parse_dvb_description(&cnf,es_info,desc_len);
if(ret < 0)
break;
cxx_dvb_context = dvbsub_init_decoder(cnf.composition_id[0],cnf.ancillary_id[0]);
if (cxx_dvb_context == NULL)
break;
ccx_options.ts_cappid = newcappid = elementary_PID;
cap_stream_type = newcap_stream_type = ccx_stream_type;
}
}
}
if ((ccx_options.teletext_mode==CCX_TXT_AUTO_NOT_YET_FOUND ||
if (IS_FEASIBLE(ccx_options.codec,ccx_options.nocodec,CCX_CODEC_TELETEXT) && (ccx_options.teletext_mode==CCX_TXT_AUTO_NOT_YET_FOUND ||
(ccx_options.teletext_mode==CCX_TXT_IN_USE && !ccx_options.ts_cappid)) // Want teletext but don't know the PID yet
&& ccx_stream_type == CCX_STREAM_TYPE_PRIVATE_MPEG2) // MPEG-2 Packetized Elementary Stream packets containing private data
{
@ -551,6 +582,10 @@ void process_ccx_mpeg_descriptor (unsigned char *data, unsigned length)
dbg_print (CCX_DMT_PMT, " Initial page: %02X\n",teletext_page_number);
}
break;
case CCX_MPEG_DSC_DVB_SUBTITLE:
dbg_print(CCX_DMT_PMT, " DVB Subtitle descriptor\n");
break;
default:
if (data[0]==CCX_MPEG_DSC_REGISTRATION) // Registration descriptor, could be useful eventually
break;