📄 mpeg3demux.c
字号:
#include "libmpeg3.h"
#include "mpeg3io.h"
#include "mpeg3protos.h"
#include "workarounds.h"
#include <errno.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>
#define ABS(x) ((x) >= 0 ? (x) : -(x))
/* Don't advance pointer */
static __inline unsigned char packet_next_char(mpeg3_demuxer_t *demuxer)
{
//printf(__FUNCTION__ " called\n");
return demuxer->raw_data[demuxer->raw_offset];
}
/* Advance pointer */
static unsigned char packet_read_char(mpeg3_demuxer_t *demuxer)
{
unsigned char result = demuxer->raw_data[demuxer->raw_offset++];
//printf(__FUNCTION__ " called\n");
return result;
}
static __inline unsigned int packet_read_int16(mpeg3_demuxer_t *demuxer)
{
unsigned int a, b, result;
//printf(__FUNCTION__ " called\n");
a = demuxer->raw_data[demuxer->raw_offset++];
b = demuxer->raw_data[demuxer->raw_offset++];
result = (a << 8) | b;
return result;
}
static __inline unsigned int packet_next_int24(mpeg3_demuxer_t *demuxer)
{
unsigned int a, b, c, result;
//printf(__FUNCTION__ " called\n");
a = demuxer->raw_data[demuxer->raw_offset];
b = demuxer->raw_data[demuxer->raw_offset + 1];
c = demuxer->raw_data[demuxer->raw_offset + 2];
result = (a << 16) | (b << 8) | c;
return result;
}
static __inline unsigned int packet_read_int24(mpeg3_demuxer_t *demuxer)
{
unsigned int a, b, c, result;
//printf(__FUNCTION__ " called\n");
a = demuxer->raw_data[demuxer->raw_offset++];
b = demuxer->raw_data[demuxer->raw_offset++];
c = demuxer->raw_data[demuxer->raw_offset++];
result = (a << 16) | (b << 8) | c;
return result;
}
static __inline unsigned int packet_read_int32(mpeg3_demuxer_t *demuxer)
{
unsigned int a, b, c, d, result;
//printf(__FUNCTION__ " called\n");
a = demuxer->raw_data[demuxer->raw_offset++];
b = demuxer->raw_data[demuxer->raw_offset++];
c = demuxer->raw_data[demuxer->raw_offset++];
d = demuxer->raw_data[demuxer->raw_offset++];
result = (a << 24) | (b << 16) | (c << 8) | d;
return result;
}
static __inline unsigned int packet_skip(mpeg3_demuxer_t *demuxer, long length)
{
//printf(__FUNCTION__ " called\n");
demuxer->raw_offset += length;
return 0;
}
static int get_adaptation_field(mpeg3_demuxer_t *demuxer)
{
long length;
int pcr_flag;
demuxer->adaptation_fields++;
/* get adaptation field length */
length = packet_read_char(demuxer);
if(length > 0)
{
/* get first byte */
pcr_flag = (packet_read_char(demuxer) >> 4) & 1;
if(pcr_flag)
{
unsigned long clk_ref_base = packet_read_int32(demuxer);
unsigned int clk_ref_ext = packet_read_int16(demuxer);
if (clk_ref_base > 0x7fffffff)
{ /* correct for invalid numbers */
clk_ref_base = 0; /* ie. longer than 32 bits when multiplied by 2 */
clk_ref_ext = 0; /* multiplied by 2 corresponds to shift left 1 (<<=1) */
}
else
{
clk_ref_base <<= 1; /* Create space for bit */
clk_ref_base |= (clk_ref_ext >> 15); /* Take bit */
clk_ref_ext &= 0x01ff; /* Only lower 9 bits */
}
demuxer->time = ((double)clk_ref_base + clk_ref_ext / 300) / 90000;
if(length) packet_skip(demuxer, length - 7);
}
else
packet_skip(demuxer, length - 1);
}
return 0;
}
static int get_program_association_table(mpeg3_demuxer_t *demuxer)
{
demuxer->program_association_tables++;
demuxer->table_id = packet_read_char(demuxer);
demuxer->section_length = packet_read_int16(demuxer) & 0xfff;
demuxer->transport_stream_id = packet_read_int16(demuxer);
packet_skip(demuxer, demuxer->raw_size - demuxer->raw_offset);
return 0;
}
static int get_data_buffer(mpeg3_demuxer_t *demuxer)
{
while(demuxer->raw_offset < demuxer->raw_size &&
demuxer->data_size < MPEG3_RAW_SIZE)
{
demuxer->data_buffer[demuxer->data_size++] =
demuxer->raw_data[demuxer->raw_offset++];
}
return 0;
}
static int get_pes_packet_header(mpeg3_demuxer_t *demuxer, unsigned long *pts, unsigned long *dts)
{
unsigned int pes_header_bytes = 0;
unsigned int pts_dts_flags;
int pes_header_data_length;
/* drop first 8 bits */
packet_read_char(demuxer);
pts_dts_flags = (packet_read_char(demuxer) >> 6) & 0x3;
pes_header_data_length = packet_read_char(demuxer);
/* Get Presentation Time stamps and Decoding Time Stamps */
if(pts_dts_flags == 2)
{
*pts = (packet_read_char(demuxer) >> 1) & 7; /* Only low 4 bits (7==1111) */
*pts <<= 15;
*pts |= (packet_read_int16(demuxer) >> 1);
*pts <<= 15;
*pts |= (packet_read_int16(demuxer) >> 1);
pes_header_bytes += 5;
}
else if(pts_dts_flags == 3)
{
*pts = (packet_read_char(demuxer) >> 1) & 7; /* Only low 4 bits (7==1111) */
*pts <<= 15;
*pts |= (packet_read_int16(demuxer) >> 1);
*pts <<= 15;
*pts |= (packet_read_int16(demuxer) >> 1);
*dts = (packet_read_char(demuxer) >> 1) & 7; /* Only low 4 bits (7==1111) */
*dts <<= 15;
*dts |= (packet_read_int16(demuxer) >> 1);
*dts <<= 15;
*dts |= (packet_read_int16(demuxer) >> 1);
pes_header_bytes += 10;
}
demuxer->time = (double)*pts / 90000;
//printf("get_pes_packet_header %f\n", demuxer->time);
/* extract other stuff here! */
packet_skip(demuxer, pes_header_data_length - pes_header_bytes);
return 0;
}
static int get_unknown_data(mpeg3_demuxer_t *demuxer)
{
packet_skip(demuxer, demuxer->raw_size - demuxer->raw_offset);
return 0;
}
// Combine the pid and the stream id into one unit
#define CUSTOM_ID(pid, stream_id) (((pid << 8) | stream_id) & 0xffff)
static int get_pes_packet_data(mpeg3_demuxer_t *demuxer, unsigned int stream_id)
{
unsigned long pts = 0, dts = 0;
get_pes_packet_header(demuxer, &pts, &dts);
//printf("get_pes_packet_data %x\n", CUSTOM_ID(demuxer->pid, stream_id));
if(stream_id == 0xbd)
{
// Don't know if the next byte is the true stream id like in program stream
stream_id = 0x0;
if(demuxer->read_all)
demuxer->astream_table[CUSTOM_ID(demuxer->pid, stream_id)] = AUDIO_AC3;
if(demuxer->astream == -1)
demuxer->astream = CUSTOM_ID(demuxer->pid, stream_id);
if(CUSTOM_ID(demuxer->pid, stream_id) == demuxer->astream &&
demuxer->do_audio)
{
// get_pes_packet_header(demuxer, &pts, &dts);
demuxer->pes_audio_time = pts;
demuxer->audio_pid = demuxer->pid;
return get_data_buffer(demuxer);
}
}
else
if((stream_id >> 4) == 12 || (stream_id >> 4) == 13)
{
/* Just pick the first available stream if no ID is set */
//printf("get_pes_packet_data audio %x\n", stream_id);
if(demuxer->read_all)
demuxer->astream_table[CUSTOM_ID(demuxer->pid, stream_id)] = AUDIO_MPEG;
if(demuxer->astream == -1)
demuxer->astream = CUSTOM_ID(demuxer->pid, stream_id);
if(CUSTOM_ID(demuxer->pid, stream_id) == demuxer->astream &&
demuxer->do_audio)
{
// get_pes_packet_header(demuxer, &pts, &dts);
demuxer->pes_audio_time = pts;
demuxer->audio_pid = demuxer->pid;
return get_data_buffer(demuxer);
}
}
else
if((stream_id >> 4) == 14)
{
//printf("get_pes_packet_data video %x\n", stream_id);
/* Just pick the first available stream if no ID is set */
if(demuxer->read_all)
demuxer->vstream_table[CUSTOM_ID(demuxer->pid, stream_id)] = 1;
else
if(demuxer->vstream == -1)
demuxer->vstream = (CUSTOM_ID(demuxer->pid, stream_id));
if(CUSTOM_ID(demuxer->pid, stream_id) == demuxer->vstream &&
demuxer->do_video)
{
// get_pes_packet_header(demuxer, &pts, &dts);
demuxer->pes_video_time = pts;
demuxer->video_pid = demuxer->pid;
return get_data_buffer(demuxer);
}
}
else
{
return get_unknown_data(demuxer);
}
packet_skip(demuxer, demuxer->raw_size - demuxer->raw_offset);
return 0;
}
static int get_pes_packet(mpeg3_demuxer_t *demuxer)
{
unsigned int stream_id;
demuxer->pes_packets++;
/* Skip startcode */
packet_read_int24(demuxer);
stream_id = packet_read_char(demuxer);
/* Skip pes packet length */
packet_read_int16(demuxer);
if(stream_id != MPEG3_PRIVATE_STREAM_2 &&
stream_id != MPEG3_PADDING_STREAM)
{
return get_pes_packet_data(demuxer, stream_id);
}
else
if(stream_id == MPEG3_PRIVATE_STREAM_2)
{
/* Dump private data! */
fprintf(stderr, "stream_id == MPEG3_PRIVATE_STREAM_2\n");
packet_skip(demuxer, demuxer->raw_size - demuxer->raw_offset);
return 0;
}
else
if(stream_id == MPEG3_PADDING_STREAM)
{
packet_skip(demuxer, demuxer->raw_size - demuxer->raw_offset);
return 0;
}
else
{
fprintf(stderr, "unknown stream_id in pes packet");
return 1;
}
return 0;
}
static int get_payload(mpeg3_demuxer_t *demuxer)
{
//printf("get_payload 1 %x %d\n", demuxer->pid, demuxer->payload_unit_start_indicator);
if(demuxer->payload_unit_start_indicator)
{
if(demuxer->pid==0) get_program_association_table(demuxer);
else
if(packet_next_int24(demuxer) == MPEG3_PACKET_START_CODE_PREFIX) get_pes_packet(demuxer);
else
packet_skip(demuxer, demuxer->raw_size - demuxer->raw_offset);
}
else
{
//printf("get_payload 2\n");
if(demuxer->pid == demuxer->audio_pid && demuxer->do_audio)
{
get_data_buffer(demuxer);
}
else
if(demuxer->pid == demuxer->video_pid && demuxer->do_video)
{
get_data_buffer(demuxer);
}
else
packet_skip(demuxer, demuxer->raw_size - demuxer->raw_offset);
}
return 0;
}
/* Read a transport packet */
static int read_transport(mpeg3_demuxer_t *demuxer)
{
mpeg3_t *file = (mpeg3_t*)demuxer->file;
mpeg3_title_t *title = demuxer->titles[demuxer->current_title];
int result = 0;
unsigned int bits;
int table_entry;
//printf("read_transport 1 %d\n", file->packet_size);
/* Packet size is known for transport streams */
demuxer->raw_size = file->packet_size;
demuxer->raw_offset = 0;
if(result)
{
perror("read_transport");
return 1;
}
//printf("read transport 1\n");
// Search for Sync byte */
do
{
bits = mpeg3io_read_char(title->fs);
}while(!mpeg3io_eof(title->fs) && !result && bits != MPEG3_SYNC_BYTE);
//printf("read transport 2 bits=%x tell=%llx packet_size=%x\n", bits, mpeg3io_tell(title->fs), file->packet_size);
if(bits == MPEG3_SYNC_BYTE && !result)
{
demuxer->raw_data[0] = MPEG3_SYNC_BYTE;
result = mpeg3io_read_data(demuxer->raw_data + 1,
file->packet_size - 1,
title->fs);
}
else
return 1;
packet_read_char(demuxer);
bits = packet_read_int24(demuxer) & 0x00ffffff;
//printf("read transport 3 tell=%x bits=%x\n", mpeg3io_tell(title->fs), bits);
demuxer->transport_error_indicator = (bits >> 23) & 0x1;
demuxer->payload_unit_start_indicator = (bits >> 22) & 0x1;
demuxer->pid = (bits >> 8) & 0x00001fff;
demuxer->transport_scrambling_control = (bits >> 6) & 0x3;
demuxer->adaptation_field_control = (bits >> 4) & 0x3;
demuxer->continuity_counter = bits & 0xf;
//printf("read_transport 4 %x\n", demuxer->pid);
if(demuxer->transport_error_indicator)
{
fprintf(stderr, "demuxer->transport_error_indicator\n");
return 1;
}
//printf("read_transport 5 %x\n", demuxer->pid);
if (demuxer->pid == 0x1fff)
{
demuxer->is_padding = 1; /* padding; just go to next */
return 0;
}
else
{
demuxer->is_padding = 0;
}
//printf("read_transport 6 %x\n", demuxer->pid);
/* Get pid */
for(table_entry = 0, result = 0;
table_entry < demuxer->total_pids;
table_entry++)
{
if(demuxer->pid == demuxer->pid_table[table_entry])
{
result = 1;
break;
}
}
//printf("read_transport 7 %x\n", demuxer->pid);
/* Not in pid table */
if(!result)
{
demuxer->pid_table[table_entry] = demuxer->pid;
demuxer->continuity_counters[table_entry] = demuxer->continuity_counter; /* init */
demuxer->total_pids++;
//printf("read_transport program id detected %x\n", demuxer->pid);
}
result = 0;
#if 0
/* Check counters */
if(demuxer->pid != MPEG3_PROGRAM_ASSOCIATION_TABLE &&
demuxer->pid != MPEG3_CONDITIONAL_ACCESS_TABLE &&
(demuxer->adaptation_field_control == 1 || demuxer->adaptation_field_control == 3))
{
if(demuxer->continuity_counters[table_entry] != demuxer->continuity_counter)
{
// fprintf(stderr, "demuxer->continuity_counters[table_entry] != demuxer->continuity_counter\n");
/* Reset it */
demuxer->continuity_counters[table_entry] = demuxer->continuity_counter;
}
if(++(demuxer->continuity_counters[table_entry]) > 15) demuxer->continuity_counters[table_entry] = 0;
}
#endif
//printf("read_transport 8 %x %x\n", demuxer->adaptation_field_control, demuxer->pid);
if(demuxer->adaptation_field_control == 2 ||
demuxer->adaptation_field_control == 3)
result = get_adaptation_field(demuxer);
// Need to enter in astream and vstream table:
// PID ored with stream_id
if(demuxer->adaptation_field_control == 1 ||
demuxer->adaptation_field_control == 3)
result = get_payload(demuxer);
return result;
}
static int get_system_header(mpeg3_demuxer_t *demuxer)
{
mpeg3_title_t *title = demuxer->titles[demuxer->current_title];
int length = mpeg3io_read_int16(title->fs);
mpeg3io_seek_relative(title->fs, length);
return 0;
}
static unsigned long get_timestamp(mpeg3_demuxer_t *demuxer)
{
unsigned long timestamp;
mpeg3_title_t *title = demuxer->titles[demuxer->current_title];
/* Only low 4 bits (7==1111) */
timestamp = (mpeg3io_read_char(title->fs) >> 1) & 7;
timestamp <<= 15;
timestamp |= (mpeg3io_read_int16(title->fs) >> 1);
timestamp <<= 15;
timestamp |= (mpeg3io_read_int16(title->fs) >> 1);
return timestamp;
}
static int get_pack_header(mpeg3_demuxer_t *demuxer)
{
unsigned long i, j;
unsigned long clock_ref, clock_ref_ext;
mpeg3_title_t *title = demuxer->titles[demuxer->current_title];
/* Get the time code */
if((mpeg3io_next_char(title->fs) >> 4) == 2)
{
/* MPEG-1 */
demuxer->time = (double)get_timestamp(demuxer) / 90000;
/* Skip 3 bytes */
mpeg3io_read_int24(title->fs);
}
else
if(mpeg3io_next_char(title->fs) & 0x40)
{
i = mpeg3io_read_int32(title->fs);
j = mpeg3io_read_int16(title->fs);
if(i & 0x40000000 || (i >> 28) == 2)
{
clock_ref = ((i & 0x38000000) << 3);
clock_ref |= ((i & 0x03fff800) << 4);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -