kopia lustrzana https://github.com/kierank/libmpegts
195 wiersze
7.0 KiB
C
195 wiersze
7.0 KiB
C
/*****************************************************************************
|
|
* libmpegts.c :
|
|
*****************************************************************************
|
|
* Copyright (C) 2010 Kieran Kunhya
|
|
*
|
|
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA.
|
|
*****************************************************************************/
|
|
|
|
#include "common.h"
|
|
#include "codecs.h"
|
|
#include "atsc/atsc.h"
|
|
#include "cablelabs/cablelabs.h"
|
|
#include "dvb/dvb.h"
|
|
#include "hdmv/hdmv.h"
|
|
#include "isdb/isdb.h"
|
|
#include "crc/crc.h"
|
|
#include <math.h>
|
|
|
|
static int steam_type_table[23][2] =
|
|
{
|
|
{ LIBMPEGTS_VIDEO_MPEG2, VIDEO_MPEG2 },
|
|
{ LIBMPEGTS_VIDEO_H264, VIDEO_H264 },
|
|
{ LIBMPEGTS_AUDIO_MPEG1, AUDIO_MPEG1 },
|
|
{ LIBMPEGTS_AUDIO_MPEG2, AUDIO_MPEG2 },
|
|
{ LIBMPEGTS_AUDIO_ADTS, AUDIO_ADTS },
|
|
{ LIBMPEGTS_AUDIO_LATM, AUDIO_LATM },
|
|
{ LIBMPEGTS_AUDIO_AC3, AUDIO_AC3 }, /* ATSC/Generic */
|
|
{ LIBMPEGTS_AUDIO_AC3, PRIVATE_DATA }, /* DVB */
|
|
{ LIBMPEGTS_AUDIO_EAC3, AUDIO_EAC3 }, /* ATSC/Generic */
|
|
{ LIBMPEGTS_AUDIO_EAC3, PRIVATE_DATA }, /* DVB */
|
|
{ LIBMPEGTS_AUDIO_LPCM, AUDIO_LPCM },
|
|
{ LIBMPEGTS_AUDIO_DTS, AUDIO_DTS },
|
|
{ LIBMPEGTS_AUDIO_DOLBY_LOSSLESS, AUDIO_DOLBY_LOSSLESS },
|
|
{ LIBMPEGTS_AUDIO_DTS_HD, AUDIO_DTS_HD },
|
|
{ LIBMPEGTS_AUDIO_DTS_HD_XLL, AUDIO_DTS_HD_XLL },
|
|
{ LIBMPEGTS_AUDIO_EAC3_SECONDARY, AUDIO_EAC3_SECONDARY },
|
|
{ LIBMPEGTS_AUDIO_DTS_HD_SECONDARY, AUDIO_DTS_HD_SECONDARY },
|
|
{ LIBMPEGTS_SUB_PRESENTATION_GRAPHICS, SUB_PRESENTATION_GRAPHICS },
|
|
{ LIBMPEGTS_SUB_INTERACTIVE_GRAPHICS, SUB_INTERACTIVE_GRAPHICS },
|
|
{ LIBMPEGTS_SUB_TEXT, SUB_TEXT },
|
|
{ LIBMPEGTS_AUDIO_302M, PRIVATE_DATA },
|
|
{ LIBMPEGTS_SUB_DVB, PRIVATE_DATA },
|
|
{ 0 },
|
|
};
|
|
int write_padding( bs_t *s, uint64_t start )
|
|
{
|
|
bs_flush( s );
|
|
uint8_t *p_start = s->p_start;
|
|
int padding_bytes = TS_PACKET_SIZE - (bs_pos( s ) - start) / 8;
|
|
|
|
memset( s->p, 0xff, padding_bytes );
|
|
s->p += padding_bytes;
|
|
|
|
bs_init( s, s->p, s->p_end - s->p );
|
|
s->p_start = p_start;
|
|
|
|
return padding_bytes;
|
|
}
|
|
|
|
void write_bytes( bs_t *s, uint8_t *bytes, int length )
|
|
{
|
|
bs_flush( s );
|
|
uint8_t *p_start = s->p_start;
|
|
|
|
memcpy( s->p, bytes, length );
|
|
s->p += length;
|
|
|
|
bs_init( s, s->p, s->p_end - s->p );
|
|
s->p_start = p_start;
|
|
}
|
|
|
|
/**** Descriptors ****/
|
|
/* Registration Descriptor */
|
|
void write_registration_descriptor( bs_t *s, int descriptor_tag, int descriptor_length, char *format_id )
|
|
{
|
|
bs_write( s, 8, descriptor_tag ); // descriptor_tag
|
|
bs_write( s, 8, descriptor_length ); // descriptor_length
|
|
while( *format_id != '\0' )
|
|
bs_write( s, 8, *format_id++ ); // format_identifier
|
|
}
|
|
|
|
/* First loop of PMT Descriptors */
|
|
static void write_smoothing_buffer_descriptor( bs_t *s, ts_int_program_t *program )
|
|
{
|
|
bs_write( s, 8, SMOOTHING_BUFFER_DESCRIPTOR_TAG ); // descriptor_tag
|
|
bs_write( s, 8, 0x4 ); // descriptor_length
|
|
|
|
bs_write( s, 2, 0x3 ); // reserved
|
|
bs_write( s, 22, program->sb_leak_rate ); // sb_leak_rate
|
|
bs_write( s, 2, 0x3 ); // reserved
|
|
bs_write( s, 22, program->sb_size ); // sb_size
|
|
}
|
|
|
|
/* Second loop of PMT Descriptors */
|
|
static void write_video_stream_descriptor( bs_t *s, ts_int_stream_t *stream )
|
|
{
|
|
bs_write( s, 8, VIDEO_STREAM_DESCRIPTOR_TAG ); // descriptor_tag
|
|
bs_write( s, 8, 0x04 ); // descriptor_length
|
|
|
|
bs_write1( s, 0 ); // multiple_frame_rate_flag
|
|
bs_write( s, 4, 0 ); // frame_rate_code FIXME
|
|
bs_write1( s, 0 ); // MPEG_1_only_flag
|
|
bs_write1( s, 0 ); // constrained_parameter_flag
|
|
bs_write1( s, 0 ); // still_picture_flag
|
|
bs_write( s, 8, 0 ); // profile_and_level_indication FIXME
|
|
bs_write( s, 2, 0 ); // chroma_format FIXME
|
|
bs_write1( s, 0 ); // frame_rate_extension_flag FIXME
|
|
bs_write( s, 5, 0x1f ); // reserved
|
|
}
|
|
|
|
static void write_avc_descriptor( bs_t *s, ts_int_stream_t *stream )
|
|
{
|
|
bs_write( s, 8, AVC_DESCRIPTOR_TAG ); // descriptor_tag
|
|
bs_write( s, 8, 0x04 ); // descriptor_length
|
|
|
|
bs_write( s, 8, stream->mpegvideo_ctx->profile & 0xff ); // profile_idc
|
|
|
|
bs_write1( s, stream->mpegvideo_ctx->profile == H264_BASELINE ); // constraint_set0_flag
|
|
bs_write1( s, stream->mpegvideo_ctx->profile <= H264_MAIN ); // constraint_set1_flag
|
|
bs_write1( s, 0 ); // constraint_set2_flag
|
|
|
|
bs_write( s, 5, 0 ); // reserved
|
|
bs_write( s, 8, stream->mpegvideo_ctx->level & 0xff ); // level_idc
|
|
bs_write( s, 1, 0 ); // AVC_still_present
|
|
bs_write( s, 1, 0 ); // AVC_24_hour_picture_flag
|
|
bs_write( s, 6, 0x3f ); // reserved
|
|
}
|
|
static void write_iso_lang_descriptor( bs_t *s, ts_int_stream_t *stream )
|
|
{
|
|
bs_write( s, 8, ISO_693_LANGUAGE_DESCRIPTOR_TAG ); // descriptor_tag
|
|
bs_write( s, 8, 0x04 ); // descriptor_length
|
|
for( int i = 0; i < 3; i++ )
|
|
bs_write( s, 8, stream->lang_code[i] );
|
|
|
|
bs_write(s, 8, 0 ); // audio_type
|
|
}
|
|
static void write_timestamp( bs_t *s, uint64_t timestamp )
|
|
{
|
|
bs_write( s, 3, (timestamp >> 30) & 0x07 ); // timestamp [32..30]
|
|
bs_write1( s, 1 ); // marker_bit
|
|
bs_write( s, 8, (timestamp >> 22) & 0xff ); // timestamp [29..15]
|
|
bs_write( s, 7, (timestamp >> 15) & 0x7f ); // timestamp [29..15]
|
|
bs_write1( s, 1 ); // marker_bit
|
|
bs_write( s, 8, (timestamp >> 7) & 0xff ); // timestamp [14..0]
|
|
bs_write( s, 7, timestamp & 0x7f ); // timestamp [14..0]
|
|
bs_write1( s, 1 ); // marker_bit
|
|
}
|
|
|
|
void write_crc( bs_t *s, uint64_t start )
|
|
{
|
|
uint8_t *p_start = s->p_start;
|
|
int pos = (bs_pos( s ) - start) / 8;
|
|
uint32_t crc = crc_32( s->p - pos, pos );
|
|
|
|
bs_init( s, s->p, s->p_end - s->p );
|
|
s->p_start = p_start;
|
|
|
|
bs_write32( s, crc );
|
|
}
|
|
static void write_null_packet( ts_writer_t *w )
|
|
{
|
|
uint64_t start;
|
|
int cc = 0;
|
|
|
|
bs_t *s = &w->out.bs;
|
|
start = bs_pos( s );
|
|
|
|
write_packet_header( w, 0, NULL_PID, PAYLOAD_ONLY, &cc );
|
|
write_padding( s, start );
|
|
|
|
increase_pcr( w, 1 );
|
|
}
|
|
|
|
ts_int_stream_t *find_stream( ts_writer_t *w, int pid )
|
|
{
|
|
for( int i = 0; i < w->programs[0]->num_streams; i++ )
|
|
{
|
|
if( pid == w->programs[0]->streams[i]->pid )
|
|
return w->programs[0]->streams[i];
|
|
}
|
|
return NULL;
|
|
}
|