You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1370 lines
32 KiB
1370 lines
32 KiB
4 years ago
|
/*
|
||
|
* scan_pes.c
|
||
|
*
|
||
|
* Copyright (C) Thomas Oestreich - June 2001
|
||
|
*
|
||
|
* This file is part of transcode, a video stream processing tool
|
||
|
*
|
||
|
* transcode 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, or (at your option)
|
||
|
* any later version.
|
||
|
*
|
||
|
* transcode 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 GNU Make; see the file COPYING. If not, write to
|
||
|
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
#include "transcode.h"
|
||
|
#include "tcinfo.h"
|
||
|
#include "ioaux.h"
|
||
|
#include "tc.h"
|
||
|
#include "aux_pes.h"
|
||
|
#include "mpg123.h"
|
||
|
#include "ac3scan.h"
|
||
|
#include "demuxer.h"
|
||
|
#include "libtc/libtc.h"
|
||
|
#include "libtc/ratiocodes.h"
|
||
|
|
||
|
#define BUFFER_SIZE 262144
|
||
|
static uint8_t buffer[BUFFER_SIZE];
|
||
|
|
||
|
static seq_info_t si;
|
||
|
|
||
|
static int mpeg_version=0;
|
||
|
|
||
|
static int unit_ctr=0, seq_ctr=0;
|
||
|
|
||
|
static uint16_t id;
|
||
|
|
||
|
static uint32_t stream[256], track[TC_MAX_AUD_TRACKS], attr[TC_MAX_AUD_TRACKS];
|
||
|
|
||
|
static int tot_seq_ctr=0, tot_unit_ctr=0;
|
||
|
static unsigned int tot_bitrate=0, min_bitrate=(unsigned int)-1, max_bitrate=0;
|
||
|
|
||
|
//count packs for each presntation unit
|
||
|
static uint32_t unit_pack_cnt[256], unit_pack_cnt_index=0;
|
||
|
|
||
|
static int ref_pts=0;
|
||
|
|
||
|
static int show_seq_info=0, show_ext_info=0;
|
||
|
|
||
|
static int cmp_32_bits(char *buf, long x)
|
||
|
{
|
||
|
|
||
|
if ((uint8_t)buf[0] != ((x >> 24) & 0xff))
|
||
|
return 0;
|
||
|
if ((uint8_t)buf[1] != ((x >> 16) & 0xff))
|
||
|
return 0;
|
||
|
if ((uint8_t)buf[2] != ((x >> 8) & 0xff))
|
||
|
return 0;
|
||
|
if ((uint8_t)buf[3] != ((x ) & 0xff))
|
||
|
return 0;
|
||
|
|
||
|
// OK found it
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
static int probe_sequence(uint8_t *buffer, ProbeInfo *probe_info)
|
||
|
{
|
||
|
|
||
|
int horizontal_size;
|
||
|
int vertical_size;
|
||
|
int aspect_ratio_information;
|
||
|
int frame_rate_code;
|
||
|
int bit_rate_value;
|
||
|
int vbv_buffer_size_value;
|
||
|
int constrained_parameters_flag;
|
||
|
int load_intra_quantizer_matrix;
|
||
|
int load_non_intra_quantizer_matrix;
|
||
|
|
||
|
vertical_size = (buffer[0] << 16) | (buffer[1] << 8) | buffer[2];
|
||
|
horizontal_size = ((vertical_size >> 12) + 15) & ~15;
|
||
|
vertical_size = ((vertical_size & 0xfff) + 15) & ~15;
|
||
|
|
||
|
aspect_ratio_information = buffer[3] >> 4;
|
||
|
frame_rate_code = buffer[3] & 15;
|
||
|
bit_rate_value = (buffer[4] << 10) | (buffer[5] << 2) | (buffer[6] >> 6);
|
||
|
vbv_buffer_size_value = ((buffer[6] << 5) | (buffer[7] >> 3)) & 0x3ff;
|
||
|
constrained_parameters_flag = buffer[7] & 4;
|
||
|
load_intra_quantizer_matrix = buffer[7] & 2;
|
||
|
if (load_intra_quantizer_matrix)
|
||
|
buffer += 64;
|
||
|
load_non_intra_quantizer_matrix = buffer[7] & 1;
|
||
|
|
||
|
//set some defaults, if invalid:
|
||
|
if(aspect_ratio_information < 0 || aspect_ratio_information>15) aspect_ratio_information=0;
|
||
|
|
||
|
if(frame_rate_code < 0 || frame_rate_code>15) frame_rate_code=0;
|
||
|
|
||
|
//fill out user structure
|
||
|
|
||
|
probe_info->width = horizontal_size;
|
||
|
probe_info->height = vertical_size;
|
||
|
probe_info->asr = aspect_ratio_information;
|
||
|
probe_info->frc = frame_rate_code;
|
||
|
probe_info->bitrate = bit_rate_value * 400.0 / 1000.0;
|
||
|
tc_frc_code_to_value(frame_rate_code, &probe_info->fps);
|
||
|
|
||
|
return(0);
|
||
|
|
||
|
}
|
||
|
|
||
|
static int probe_extension(uint8_t *buffer, ProbeInfo *probe_info)
|
||
|
{
|
||
|
|
||
|
int intra_dc_precision;
|
||
|
int picture_structure;
|
||
|
int top_field_first;
|
||
|
int frame_pred_frame_dct;
|
||
|
int concealment_motion_vectors;
|
||
|
int q_scale_type;
|
||
|
int intra_vlc_format;
|
||
|
int alternate_scan;
|
||
|
int repeat_first_field;
|
||
|
int progressive_frame;
|
||
|
|
||
|
intra_dc_precision = (buffer[2] >> 2) & 3;
|
||
|
picture_structure = buffer[2] & 3;
|
||
|
top_field_first = buffer[3] >> 7;
|
||
|
frame_pred_frame_dct = (buffer[3] >> 6) & 1;
|
||
|
concealment_motion_vectors = (buffer[3] >> 5) & 1;
|
||
|
q_scale_type = (buffer[3] >> 4) & 1;
|
||
|
intra_vlc_format = (buffer[3] >> 3) & 1;
|
||
|
alternate_scan = (buffer[3] >> 2) & 1;
|
||
|
repeat_first_field = (buffer[3] >> 1) & 1;
|
||
|
progressive_frame = buffer[4] >> 7;
|
||
|
|
||
|
//get infos
|
||
|
probe_info->ext_attributes[2] = progressive_frame;
|
||
|
probe_info->ext_attributes[3] = alternate_scan;
|
||
|
|
||
|
if(top_field_first == 1 && repeat_first_field == 0) return(1);
|
||
|
|
||
|
return(0);
|
||
|
}
|
||
|
|
||
|
static void unit_summary(void)
|
||
|
{
|
||
|
int n;
|
||
|
|
||
|
int pes_total=0;
|
||
|
|
||
|
tc_log_msg(__FILE__, "------------- presentation unit [%d] ---------------", unit_ctr);
|
||
|
|
||
|
for(n=0; n<256; ++n) {
|
||
|
if(stream[n] && n != 0xba)
|
||
|
tc_log_msg(__FILE__, "stream id [0x%x] %6d", n, stream[n]);
|
||
|
|
||
|
if(n != 0xba) pes_total+=stream[n];
|
||
|
stream[n]=0; //reset or next unit
|
||
|
}
|
||
|
|
||
|
tc_log_msg(__FILE__, "%d packetized elementary stream(s) PES packets found", pes_total);
|
||
|
|
||
|
tc_log_msg(__FILE__, "presentation unit PU [%d] contains %d MPEG video sequence(s)", unit_ctr, seq_ctr);
|
||
|
if (seq_ctr) {
|
||
|
tc_log_msg(__FILE__, "Average Bitrate is %u. Min Bitrate is %u, max is %u (%s)",
|
||
|
((tot_bitrate*400)/1000)/seq_ctr, min_bitrate*400/1000, max_bitrate*400/1000,
|
||
|
(max_bitrate==min_bitrate)?"CBR":"VBR");
|
||
|
}
|
||
|
|
||
|
++tot_unit_ctr;
|
||
|
tot_seq_ctr+=seq_ctr;
|
||
|
|
||
|
tc_log_msg(__FILE__, "---------------------------------------------------");
|
||
|
|
||
|
//reset counters
|
||
|
seq_ctr=0;
|
||
|
show_seq_info=0;
|
||
|
|
||
|
fflush(stdout);
|
||
|
}
|
||
|
|
||
|
static int mpeg1_skip_table[16] = {
|
||
|
1, 0xffff, 5, 10, 0xffff, 0xffff, 0xffff, 0xffff,
|
||
|
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff
|
||
|
};
|
||
|
|
||
|
/*------------------------------------------------------------------
|
||
|
*
|
||
|
* full source scan mode:
|
||
|
*
|
||
|
*------------------------------------------------------------------*/
|
||
|
|
||
|
/*
|
||
|
* helper. Ok, that's no much more than a crude movement from
|
||
|
* probe_stream. Isn't really a big leap forward. Yet.
|
||
|
*/
|
||
|
static void adjust_info(info_t *ipipe)
|
||
|
{
|
||
|
switch(ipipe->magic) {
|
||
|
case TC_MAGIC_CDXA:
|
||
|
ipipe->probe_info->attributes |= TC_INFO_NO_DEMUX;
|
||
|
break;
|
||
|
|
||
|
case TC_MAGIC_MPEG_PS: /* MPEG Program Stream */
|
||
|
case TC_MAGIC_VOB: /* backward compatibility fallback */
|
||
|
/* NTSC video/film check */
|
||
|
if (verbose >= TC_DEBUG) {
|
||
|
tc_log_msg(__FILE__, "att0=%d, att1=%d",
|
||
|
ipipe->probe_info->ext_attributes[0],
|
||
|
ipipe->probe_info->ext_attributes[1]);
|
||
|
}
|
||
|
if (ipipe->probe_info->codec == TC_CODEC_MPEG2
|
||
|
&& ipipe->probe_info->height == 480
|
||
|
&& ipipe->probe_info->width == 720) {
|
||
|
if (ipipe->probe_info->ext_attributes[0] > 2 * ipipe->probe_info->ext_attributes[1]
|
||
|
|| ipipe->probe_info->ext_attributes[1] == 0) {
|
||
|
ipipe->probe_info->is_video = 1;
|
||
|
}
|
||
|
|
||
|
if (ipipe->probe_info->is_video) {
|
||
|
ipipe->probe_info->fps = NTSC_VIDEO;
|
||
|
ipipe->probe_info->frc = 4;
|
||
|
} else {
|
||
|
ipipe->probe_info->fps = NTSC_FILM;
|
||
|
ipipe->probe_info->frc = 1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (ipipe->probe_info->codec == TC_CODEC_MPEG1) {
|
||
|
ipipe->probe_info->magic = TC_MAGIC_MPEG_PS;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* check for need of special import module,
|
||
|
* that does not rely on 2k packs
|
||
|
*/
|
||
|
if (ipipe->probe_info->attributes & TC_INFO_NO_DEMUX) {
|
||
|
ipipe->probe_info->codec = TC_CODEC_MPEG;
|
||
|
ipipe->probe_info->magic = TC_MAGIC_MPEG_PS; /* XXX: doubtful */
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case TC_MAGIC_MPEG_ES: /* MPEG Elementary Stream */
|
||
|
case TC_MAGIC_M2V: /* backward compatibility fallback */
|
||
|
/* make sure not to use the demuxer */
|
||
|
ipipe->probe_info->codec = TC_CODEC_MPEG;
|
||
|
ipipe->probe_info->magic = TC_MAGIC_MPEG_ES;
|
||
|
break;
|
||
|
|
||
|
case TC_MAGIC_MPEG_PES:/* MPEG Packetized Elementary Stream */
|
||
|
case TC_MAGIC_MPEG: /* backward compatibility fallback */
|
||
|
ipipe->probe_info->attributes |= TC_INFO_NO_DEMUX;
|
||
|
break;
|
||
|
}
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
void scan_pes(int verbose, FILE *in_file)
|
||
|
{
|
||
|
int n, has_pts_dts=0;
|
||
|
unsigned long i_pts, i_dts;
|
||
|
|
||
|
uint8_t * buf;
|
||
|
uint8_t * end;
|
||
|
uint8_t * tmp1=NULL;
|
||
|
uint8_t * tmp2=NULL;
|
||
|
int complain_loudly;
|
||
|
|
||
|
long int pack_header_last=0, pack_header_ctr=0, pack_header_pos=0, pack_header_inc=0;
|
||
|
|
||
|
char scan_buf[256];
|
||
|
|
||
|
complain_loudly = 1;
|
||
|
buf = buffer;
|
||
|
|
||
|
for(n=0; n<256; ++n) stream[n]=0;
|
||
|
|
||
|
do {
|
||
|
end = buf + fread (buf, 1, buffer + BUFFER_SIZE - buf, in_file);
|
||
|
buf = buffer;
|
||
|
|
||
|
//scan buffer
|
||
|
while (buf + 4 <= end) {
|
||
|
|
||
|
// check for valid start code
|
||
|
if (buf[0] || buf[1] || (buf[2] != 0x01)) {
|
||
|
if (complain_loudly) {
|
||
|
|
||
|
tc_log_warn(__FILE__, "missing start code at %#lx",
|
||
|
ftell (in_file) - (end - buf));
|
||
|
if ((buf[0] == 0) && (buf[1] == 0) && (buf[2] == 0))
|
||
|
tc_log_warn(__FILE__, "incorrect zero-byte padding detected - ignored");
|
||
|
|
||
|
complain_loudly = 0;
|
||
|
}
|
||
|
buf++;
|
||
|
continue;
|
||
|
}// check for valid start code
|
||
|
|
||
|
|
||
|
id = buf[3] & 0xff;
|
||
|
|
||
|
|
||
|
switch (buf[3]) {
|
||
|
|
||
|
case 0xb9: /* program end code */
|
||
|
|
||
|
tc_log_msg(__FILE__, "found program end code [0x%x]", buf[3] & 0xff);
|
||
|
|
||
|
goto summary;
|
||
|
|
||
|
case 0xba: /* pack header */
|
||
|
|
||
|
pack_header_pos = ftell (in_file) - (end - buf);
|
||
|
pack_header_inc = pack_header_pos - pack_header_last;
|
||
|
|
||
|
if (pack_header_inc==0) {
|
||
|
tc_log_msg(__FILE__, "found first packet header at stream offset 0x%#x", 0);
|
||
|
} else {
|
||
|
if((pack_header_inc-((pack_header_inc>>11)<<11)))
|
||
|
tc_log_msg(__FILE__, "pack header out of sequence at %#lx (+%#lx)", pack_header_ctr, pack_header_inc);
|
||
|
}
|
||
|
|
||
|
pack_header_last=pack_header_pos;
|
||
|
++pack_header_ctr;
|
||
|
++stream[id];
|
||
|
|
||
|
/* skip */
|
||
|
if ((buf[4] & 0xc0) == 0x40) /* mpeg2 */
|
||
|
tmp1 = buf + 14 + (buf[13] & 7);
|
||
|
else if ((buf[4] & 0xf0) == 0x20) /* mpeg1 */
|
||
|
tmp1 = buf + 12;
|
||
|
else if (buf + 5 > end)
|
||
|
goto copy;
|
||
|
else {
|
||
|
tc_log_error(__FILE__, "weird pack header");
|
||
|
import_exit(1);
|
||
|
}
|
||
|
|
||
|
if (tmp1 > end)
|
||
|
goto copy;
|
||
|
buf = tmp1;
|
||
|
break;
|
||
|
|
||
|
|
||
|
case 0xbd: /* private stream 1 */
|
||
|
|
||
|
if(!stream[id]) tc_log_msg(__FILE__, "found %s stream [0x%x]", "private_stream_1", buf[3] & 0xff);
|
||
|
|
||
|
++stream[id];
|
||
|
|
||
|
tmp2 = buf + 6 + (buf[4] << 8) + buf[5];
|
||
|
if (tmp2 > end)
|
||
|
goto copy;
|
||
|
if ((buf[6] & 0xc0) == 0x80) /* mpeg2 */
|
||
|
tmp1 = buf + 9 + buf[8];
|
||
|
else { /* mpeg1 */
|
||
|
for (tmp1 = buf + 6; *tmp1 == 0xff; tmp1++)
|
||
|
if (tmp1 == buf + 6 + 16) {
|
||
|
tc_log_warn(__FILE__, "too much stuffing");
|
||
|
buf = tmp2;
|
||
|
break;
|
||
|
}
|
||
|
if ((*tmp1 & 0xc0) == 0x40)
|
||
|
tmp1 += 2;
|
||
|
tmp1 += mpeg1_skip_table [*tmp1 >> 4];
|
||
|
}
|
||
|
|
||
|
if(verbose & TC_DEBUG)
|
||
|
tc_log_msg(__FILE__, "[0x%x] (sub_id=0x%02x)", buf[3] & 0xff, *tmp1);
|
||
|
|
||
|
if((*tmp1-0x80) >= 0 && (*tmp1-0x80)<TC_MAX_AUD_TRACKS && !track[*tmp1-0x80] ) {
|
||
|
tc_log_msg(__FILE__, "found AC3 audio track %d [0x%x]", *tmp1-0x80, *tmp1);
|
||
|
track[*tmp1-0x80]=1;
|
||
|
} else if (*tmp1 == 0xFF && memcmp(tmp1+4,"SShd",4) == 0) {
|
||
|
tc_log_msg(__FILE__, "found VAG audio track [0x%x]", *tmp1);
|
||
|
track[0]=1;
|
||
|
}
|
||
|
|
||
|
buf = tmp2;
|
||
|
|
||
|
break;
|
||
|
|
||
|
case 0xbf:
|
||
|
|
||
|
if(!stream[id])
|
||
|
tc_log_msg(__FILE__, "found %s [0x%x]", "navigation pack", buf[3] & 0xff);
|
||
|
|
||
|
++stream[id];
|
||
|
|
||
|
tmp2 = buf + 6 + (buf[4] << 8) + buf[5];
|
||
|
if (tmp2 > end)
|
||
|
goto copy;
|
||
|
|
||
|
buf = tmp2;
|
||
|
|
||
|
break;
|
||
|
|
||
|
case 0xbe:
|
||
|
|
||
|
if(!stream[id])
|
||
|
tc_log_msg(__FILE__, "found %s stream [0x%x]", "padding", buf[3] & 0xff);
|
||
|
|
||
|
++stream[id];
|
||
|
|
||
|
tmp2 = buf + 6 + (buf[4] << 8) + buf[5];
|
||
|
if (tmp2 > end)
|
||
|
goto copy;
|
||
|
|
||
|
buf = tmp2;
|
||
|
|
||
|
break;
|
||
|
|
||
|
case 0xbb:
|
||
|
|
||
|
if(!stream[id])
|
||
|
tc_log_msg(__FILE__, "found %s stream [0x%x]", "unknown", buf[3] & 0xff);
|
||
|
|
||
|
++stream[id];
|
||
|
|
||
|
tmp2 = buf + 6 + (buf[4] << 8) + buf[5];
|
||
|
if (tmp2 > end)
|
||
|
goto copy;
|
||
|
|
||
|
buf = tmp2;
|
||
|
|
||
|
break;
|
||
|
|
||
|
|
||
|
//MPEG audio, maybe more???
|
||
|
|
||
|
case 0xc0:
|
||
|
case 0xc1:
|
||
|
case 0xc2:
|
||
|
case 0xc3:
|
||
|
case 0xc4:
|
||
|
case 0xc5:
|
||
|
case 0xc6:
|
||
|
case 0xc7:
|
||
|
case 0xc8:
|
||
|
case 0xc9:
|
||
|
case 0xca:
|
||
|
case 0xcb:
|
||
|
case 0xcc:
|
||
|
case 0xcd:
|
||
|
case 0xce:
|
||
|
case 0xcf:
|
||
|
case 0xd0:
|
||
|
case 0xd1:
|
||
|
case 0xd2:
|
||
|
case 0xd3:
|
||
|
case 0xd4:
|
||
|
case 0xd5:
|
||
|
case 0xd6:
|
||
|
case 0xd7:
|
||
|
case 0xd8:
|
||
|
case 0xd9:
|
||
|
case 0xda:
|
||
|
case 0xdb:
|
||
|
case 0xdc:
|
||
|
case 0xdd:
|
||
|
case 0xde:
|
||
|
case 0xdf:
|
||
|
|
||
|
if(!stream[id])
|
||
|
tc_log_msg(__FILE__, "found %s track %d [0x%x]", "ISO/IEC 13818-3 or 11172-3 MPEG audio", (buf[3] & 0xff) - 0xc0, buf[3] & 0xff);
|
||
|
|
||
|
++stream[id];
|
||
|
|
||
|
tmp2 = buf + 6 + (buf[4] << 8) + buf[5];
|
||
|
if (tmp2 > end)
|
||
|
goto copy;
|
||
|
if ((buf[6] & 0xc0) == 0x80) /* mpeg2 */
|
||
|
tmp1 = buf + 9 + buf[8];
|
||
|
else { /* mpeg1 */
|
||
|
for (tmp1 = buf + 6; *tmp1 == 0xff; tmp1++)
|
||
|
if (tmp1 == buf + 6 + 16) {
|
||
|
tc_log_warn(__FILE__, "too much stuffing");
|
||
|
buf = tmp2;
|
||
|
break;
|
||
|
}
|
||
|
if ((*tmp1 & 0xc0) == 0x40)
|
||
|
tmp1 += 2;
|
||
|
tmp1 += mpeg1_skip_table [*tmp1 >> 4];
|
||
|
}
|
||
|
|
||
|
buf = tmp2;
|
||
|
|
||
|
break;
|
||
|
|
||
|
case 0xe0: /* video */
|
||
|
case 0xe1: /* video */
|
||
|
case 0xe2: /* video */
|
||
|
case 0xe3: /* video */
|
||
|
case 0xe4: /* video */
|
||
|
case 0xe5: /* video */
|
||
|
case 0xe6: /* video */
|
||
|
case 0xe7: /* video */
|
||
|
case 0xe8: /* video */
|
||
|
case 0xe9: /* video */
|
||
|
|
||
|
id = buf[3] & 0xff;
|
||
|
|
||
|
tmp2 = buf + 6 + (buf[4] << 8) + buf[5];
|
||
|
if (tmp2 > end)
|
||
|
goto copy;
|
||
|
if ((buf[6] & 0xc0) == 0x80) {
|
||
|
/* mpeg2 */
|
||
|
tmp1 = buf + 9 + buf[8];
|
||
|
|
||
|
if(!stream[id])
|
||
|
tc_log_msg(__FILE__, "found %s stream [0x%x]", "ISO/IEC 13818-2 or 11172-2 MPEG video", buf[3] & 0xff);
|
||
|
++stream[id];
|
||
|
|
||
|
mpeg_version=2;
|
||
|
|
||
|
// get pts time stamp:
|
||
|
ac_memcpy(scan_buf, &buf[6], 16);
|
||
|
has_pts_dts=get_pts_dts(scan_buf, &i_pts, &i_dts);
|
||
|
|
||
|
if(has_pts_dts) {
|
||
|
|
||
|
if(!show_seq_info) {
|
||
|
for(n=0; n<100; ++n) {
|
||
|
|
||
|
if(cmp_32_bits(buf+n, TC_MAGIC_M2V)) {
|
||
|
stats_sequence(buf+n+4, &si);
|
||
|
show_seq_info=1;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
for(n=0; n<100; ++n) {
|
||
|
if(cmp_32_bits(buf+n, TC_MAGIC_M2V)) {
|
||
|
stats_sequence_silent(buf+n+4, &si);
|
||
|
if (si.brv>max_bitrate) max_bitrate=si.brv;
|
||
|
if (si.brv<min_bitrate) min_bitrate=si.brv;
|
||
|
tot_bitrate += si.brv;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if( ref_pts != 0 && i_pts < ref_pts) {
|
||
|
|
||
|
unit_summary();
|
||
|
unit_ctr++;
|
||
|
}
|
||
|
ref_pts=i_pts;
|
||
|
++seq_ctr;
|
||
|
}
|
||
|
|
||
|
} else {
|
||
|
/* mpeg1 */
|
||
|
|
||
|
if(!stream[id])
|
||
|
tc_log_msg(__FILE__, "found %s stream [0x%x]", "MPEG-1 video", buf[3] & 0xff);
|
||
|
++stream[id];
|
||
|
|
||
|
mpeg_version=1;
|
||
|
|
||
|
if(!show_seq_info) {
|
||
|
for(n=0; n<100; ++n) {
|
||
|
|
||
|
if(cmp_32_bits(buf+n, TC_MAGIC_M2V)) {
|
||
|
stats_sequence(buf+n+4, &si);
|
||
|
show_seq_info=1;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// get pts time stamp:
|
||
|
ac_memcpy(scan_buf, &buf[6], 16);
|
||
|
has_pts_dts=get_pts_dts(scan_buf, &i_pts, &i_dts);
|
||
|
|
||
|
if(has_pts_dts) {
|
||
|
|
||
|
if( ref_pts != 0 && i_pts < ref_pts) {
|
||
|
|
||
|
//unit_summary();
|
||
|
unit_ctr++;
|
||
|
}
|
||
|
ref_pts=i_pts;
|
||
|
|
||
|
++seq_ctr;
|
||
|
}
|
||
|
|
||
|
for (tmp1 = buf + 6; *tmp1 == 0xff; tmp1++)
|
||
|
if (tmp1 == buf + 6 + 16) {
|
||
|
tc_log_warn(__FILE__, "too much stuffing");
|
||
|
buf = tmp2;
|
||
|
break;
|
||
|
}
|
||
|
if ((*tmp1 & 0xc0) == 0x40)
|
||
|
tmp1 += 2;
|
||
|
tmp1 += mpeg1_skip_table [*tmp1 >> 4];
|
||
|
}
|
||
|
|
||
|
buf = tmp2;
|
||
|
break;
|
||
|
|
||
|
|
||
|
case 0xb3:
|
||
|
|
||
|
tc_log_msg(__FILE__, "found MPEG sequence start code [0x%x]", buf[3] & 0xff);
|
||
|
tc_log_warn(__FILE__, "looks like an elementary stream - not program stream");
|
||
|
|
||
|
stats_sequence(&buf[4], &si);
|
||
|
|
||
|
return;
|
||
|
|
||
|
break;
|
||
|
|
||
|
|
||
|
default:
|
||
|
if (buf[3] < 0xb9) {
|
||
|
tc_log_warn(__FILE__, "looks like an elementary stream - not program stream");
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
/* skip */
|
||
|
tmp1 = buf + 6 + (buf[4] << 8) + buf[5];
|
||
|
if (tmp1 > end)
|
||
|
goto copy;
|
||
|
buf = tmp1;
|
||
|
break;
|
||
|
|
||
|
} //start code selection
|
||
|
} //scan buffer
|
||
|
|
||
|
if (buf < end) {
|
||
|
copy:
|
||
|
/* we only pass here for mpeg1 ps streams */
|
||
|
memmove (buffer, buf, end - buf);
|
||
|
}
|
||
|
buf = buffer + (end - buf);
|
||
|
|
||
|
} while (end == buffer + BUFFER_SIZE);
|
||
|
|
||
|
tc_log_msg(__FILE__, "end of stream reached");
|
||
|
|
||
|
summary:
|
||
|
|
||
|
unit_summary();
|
||
|
|
||
|
tc_log_msg(__FILE__, "(%s) detected a total of %d presentation unit(s) PU and %d sequence(s)", __FILE__, tot_unit_ctr, tot_seq_ctr);
|
||
|
|
||
|
}
|
||
|
|
||
|
/*------------------------------------------------------------------
|
||
|
*
|
||
|
* probe only mode:
|
||
|
*
|
||
|
*------------------------------------------------------------------*/
|
||
|
|
||
|
|
||
|
void probe_pes(info_t *ipipe)
|
||
|
{
|
||
|
|
||
|
int n, num, has_pts_dts=0;
|
||
|
int aid, ret, initial_sync=0, has_audio=0;
|
||
|
|
||
|
unsigned long i_pts, i_dts;
|
||
|
long probe_bytes=0, total_bytes=0;
|
||
|
|
||
|
uint8_t * buf;
|
||
|
uint8_t * end;
|
||
|
uint8_t * tmp1=NULL;
|
||
|
uint8_t * tmp2=NULL;
|
||
|
|
||
|
long pack_pts_1=0, pack_pts_2=0, pack_pts_3=0;
|
||
|
|
||
|
long int pack_header_last=0, pack_header_ctr=0, pack_header_pos=0, pack_header_inc=0;
|
||
|
|
||
|
char scan_buf[256];
|
||
|
|
||
|
double pack_ppp=0;
|
||
|
|
||
|
FILE *in_file = fdopen(ipipe->fd_in, "r");
|
||
|
|
||
|
buf = buffer;
|
||
|
|
||
|
for(n=0; n<256; ++n) stream[n]=unit_pack_cnt[n]=0;
|
||
|
|
||
|
do {
|
||
|
|
||
|
probe_bytes = fread (buf, 1, buffer + BUFFER_SIZE - buf, in_file);
|
||
|
|
||
|
if(probe_bytes<0) {
|
||
|
ipipe->error=1;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
total_bytes += probe_bytes;
|
||
|
|
||
|
//limit amount of search stream bytes
|
||
|
if(total_bytes > TC_MAX_SEEK_BYTES * ipipe->factor) return;
|
||
|
|
||
|
end = buf + probe_bytes;
|
||
|
buf = buffer;
|
||
|
|
||
|
//scan buffer
|
||
|
while (buf + 4 <= end) {
|
||
|
|
||
|
// check for valid start code
|
||
|
if (buf[0] || buf[1] || (buf[2] != 0x01)) {
|
||
|
|
||
|
if (ipipe->verbose & TC_DEBUG) {
|
||
|
tc_log_warn(__FILE__, "missing start code at %#lx",
|
||
|
ftell (in_file) - (end - buf));
|
||
|
if ((buf[0] == 0) && (buf[1] == 0) && (buf[2] == 0))
|
||
|
tc_log_warn(__FILE__, "incorrect zero-byte padding detected - ignored");
|
||
|
}
|
||
|
ipipe->probe_info->attributes=TC_INFO_NO_DEMUX;
|
||
|
buf++;
|
||
|
continue;
|
||
|
}// check for valid start code
|
||
|
|
||
|
id = buf[3] & 0xff;
|
||
|
|
||
|
switch (buf[3]) {
|
||
|
|
||
|
//------------------------------
|
||
|
//
|
||
|
// packet header start/end code
|
||
|
//
|
||
|
//------------------------------
|
||
|
|
||
|
case 0xb9: /* program end code */
|
||
|
return;
|
||
|
break;
|
||
|
|
||
|
case 0xba: /* pack header */
|
||
|
|
||
|
pack_header_pos = ftell (in_file) - (end - buf);
|
||
|
pack_header_inc = pack_header_pos - pack_header_last;
|
||
|
|
||
|
if((pack_header_inc-((pack_header_inc>>11)<<11)))
|
||
|
ipipe->probe_info->attributes=TC_INFO_NO_DEMUX|TC_INFO_MPEG_PS;
|
||
|
|
||
|
pack_header_last=pack_header_pos;
|
||
|
|
||
|
++pack_header_ctr;
|
||
|
++stream[id];
|
||
|
|
||
|
/* skip */
|
||
|
if ((buf[4] & 0xc0) == 0x40) { /* mpeg2 */
|
||
|
tmp1 = buf + 14 + (buf[13] & 7);
|
||
|
ipipe->probe_info->codec=TC_CODEC_MPEG2;
|
||
|
} else if ((buf[4] & 0xf0) == 0x20) { /* mpeg1 */
|
||
|
tmp1 = buf + 12;
|
||
|
ipipe->probe_info->codec=TC_CODEC_MPEG1;
|
||
|
} else if (buf + 5 > end)
|
||
|
goto copy;
|
||
|
else {
|
||
|
tc_log_error(__FILE__, "weird pack header");
|
||
|
import_exit(1);
|
||
|
}
|
||
|
|
||
|
// get PPP - starts
|
||
|
|
||
|
ac_memcpy(scan_buf, &buf[4], 16);
|
||
|
pack_pts_2 = read_time_stamp_long(scan_buf);
|
||
|
pack_ppp = read_time_stamp(scan_buf);
|
||
|
|
||
|
if(pack_pts_2 == pack_pts_1)
|
||
|
if(ipipe->verbose & TC_DEBUG)
|
||
|
tc_log_msg(__FILE__, "SCR=%8ld (%8ld) unit=%d @ offset %10.4f (sec)", pack_pts_2, pack_pts_1, ipipe->probe_info->unit_cnt, pack_pts_1/90000.0);
|
||
|
|
||
|
if(pack_pts_2 < pack_pts_1) {
|
||
|
|
||
|
pack_pts_3 += pack_pts_1;
|
||
|
|
||
|
if(ipipe->verbose & TC_DEBUG)
|
||
|
tc_log_msg(__FILE__, "SCR=%8ld (%8ld) unit=%d @ offset %10.4f (sec)", pack_pts_2, pack_pts_1, ipipe->probe_info->unit_cnt+1, pack_pts_3/90000.0);
|
||
|
|
||
|
++unit_pack_cnt_index;
|
||
|
|
||
|
//reset all video/audio information at this point - start
|
||
|
|
||
|
memset(ipipe->probe_info, 0, sizeof(ProbeInfo));
|
||
|
for(n=0; n<256; ++n) stream[n]=0;
|
||
|
for(n=0; n<TC_MAX_AUD_TRACKS; ++n) track[n]=attr[n]=0;
|
||
|
show_seq_info=0;
|
||
|
//reset - ends
|
||
|
|
||
|
ipipe->probe_info->unit_cnt=unit_pack_cnt_index;
|
||
|
}
|
||
|
|
||
|
++unit_pack_cnt[unit_pack_cnt_index];
|
||
|
pack_pts_1 = pack_pts_2;
|
||
|
|
||
|
// get PPP - ends
|
||
|
|
||
|
if (tmp1 > end)
|
||
|
goto copy;
|
||
|
buf = tmp1;
|
||
|
|
||
|
break;
|
||
|
|
||
|
//------------------------
|
||
|
//
|
||
|
// MPEG video
|
||
|
//
|
||
|
//------------------------
|
||
|
|
||
|
case 0xe0: /* video */
|
||
|
case 0xe1: /* video */
|
||
|
case 0xe2: /* video */
|
||
|
case 0xe3: /* video */
|
||
|
case 0xe4: /* video */
|
||
|
case 0xe5: /* video */
|
||
|
case 0xe6: /* video */
|
||
|
case 0xe7: /* video */
|
||
|
case 0xe8: /* video */
|
||
|
case 0xe9: /* video */
|
||
|
|
||
|
id = buf[3] & 0xff;
|
||
|
|
||
|
tmp2 = buf + 6 + (buf[4] << 8) + buf[5];
|
||
|
if (tmp2 > end)
|
||
|
goto copy;
|
||
|
if ((buf[6] & 0xc0) == 0x80) {
|
||
|
/* mpeg2 */
|
||
|
tmp1 = buf + 9 + buf[8];
|
||
|
|
||
|
++stream[id];
|
||
|
|
||
|
mpeg_version=2;
|
||
|
ipipe->probe_info->codec=TC_CODEC_MPEG2;
|
||
|
|
||
|
// get pts time stamp:
|
||
|
ac_memcpy(scan_buf, &buf[6], 16);
|
||
|
has_pts_dts=get_pts_dts(scan_buf, &i_pts, &i_dts);
|
||
|
|
||
|
if(has_pts_dts) {
|
||
|
|
||
|
/*
|
||
|
I have no idea why the has_audio==0 is there. It seems to
|
||
|
cause problems at least for:
|
||
|
http://lists.exit1.org/pipermail/transcode-devel/2003-October/000004.html
|
||
|
I'll remove it until someone complains -- tibit
|
||
|
*/
|
||
|
#if 0
|
||
|
if(ipipe->probe_info->pts_start==0 || has_audio==0) {
|
||
|
#else
|
||
|
if(ipipe->probe_info->pts_start==0) {
|
||
|
#endif
|
||
|
ipipe->probe_info->pts_start=(double)i_pts/90000.0;
|
||
|
initial_sync=1;
|
||
|
}
|
||
|
|
||
|
if(!show_seq_info) {
|
||
|
|
||
|
for(n=0; n<128; ++n) {
|
||
|
|
||
|
if(cmp_32_bits(buf+n, TC_MAGIC_M2V)) {
|
||
|
probe_sequence(buf+n+4, ipipe->probe_info);
|
||
|
show_seq_info=1;
|
||
|
}
|
||
|
}
|
||
|
} // probe sequence header
|
||
|
}
|
||
|
|
||
|
|
||
|
if(!show_ext_info) {
|
||
|
|
||
|
int ret_code=-1;
|
||
|
int bb=tmp2-tmp1;
|
||
|
|
||
|
if(bb<0 || bb>2048) bb=2048;
|
||
|
|
||
|
for(n=0; n<bb; ++n) {
|
||
|
|
||
|
if(cmp_32_bits(buf+n, TC_MAGIC_PICEXT)
|
||
|
&& (buf[n+4]>>4)==8) {
|
||
|
|
||
|
ret_code = probe_extension(buf+n+4, ipipe->probe_info);
|
||
|
|
||
|
//ret_code
|
||
|
//-1 = invalid header
|
||
|
// 1 = (TFF=1,RFF=0)
|
||
|
// 0 else
|
||
|
|
||
|
if(ret_code==1) ++ipipe->probe_info->ext_attributes[0];
|
||
|
if(ret_code==0) ++ipipe->probe_info->ext_attributes[1];
|
||
|
|
||
|
}
|
||
|
} // probe extension header
|
||
|
|
||
|
ref_pts=i_pts;
|
||
|
++seq_ctr;
|
||
|
}
|
||
|
|
||
|
} else {
|
||
|
/* mpeg1 */
|
||
|
|
||
|
++stream[id];
|
||
|
|
||
|
mpeg_version=1;
|
||
|
|
||
|
//MPEG1 may have audio but no time stamps
|
||
|
initial_sync=1;
|
||
|
ipipe->probe_info->codec=TC_CODEC_MPEG1;
|
||
|
|
||
|
if(!show_seq_info) {
|
||
|
for(n=0; n<100; ++n) {
|
||
|
|
||
|
if(cmp_32_bits(buf+n, TC_MAGIC_M2V)) {
|
||
|
probe_sequence(buf+n+4, ipipe->probe_info);
|
||
|
show_seq_info=1;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// get pts time stamp:
|
||
|
ac_memcpy(scan_buf, &buf[6], 16);
|
||
|
has_pts_dts=get_pts_dts(scan_buf, &i_pts, &i_dts);
|
||
|
|
||
|
if(has_pts_dts) {
|
||
|
|
||
|
if( ref_pts != 0 && i_pts < ref_pts) unit_ctr++;
|
||
|
|
||
|
ref_pts=i_pts;
|
||
|
|
||
|
++seq_ctr;
|
||
|
|
||
|
if(ipipe->probe_info->pts_start==0 || has_audio==0) {
|
||
|
ipipe->probe_info->pts_start=(double)i_pts/90000.0;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
for (tmp1 = buf + 6; *tmp1 == 0xff; tmp1++)
|
||
|
if (tmp1 == buf + 6 + 16) {
|
||
|
tc_log_warn(__FILE__, "too much stuffing");
|
||
|
buf = tmp2;
|
||
|
break;
|
||
|
}
|
||
|
if ((*tmp1 & 0xc0) == 0x40)
|
||
|
tmp1 += 2;
|
||
|
tmp1 += mpeg1_skip_table [*tmp1 >> 4];
|
||
|
}
|
||
|
|
||
|
buf = tmp2;
|
||
|
break;
|
||
|
|
||
|
|
||
|
//----------------------------------
|
||
|
//
|
||
|
// private stream 1
|
||
|
//
|
||
|
//----------------------------------
|
||
|
|
||
|
|
||
|
case 0xbd:
|
||
|
|
||
|
++stream[id];
|
||
|
|
||
|
tmp2 = buf + 6 + (buf[4] << 8) + buf[5];
|
||
|
if (tmp2 > end)
|
||
|
goto copy;
|
||
|
if ((buf[6] & 0xc0) == 0x80) /* mpeg2 */
|
||
|
tmp1 = buf + 9 + buf[8];
|
||
|
else { /* mpeg1 */
|
||
|
for (tmp1 = buf + 6; *tmp1 == 0xff; tmp1++)
|
||
|
if (tmp1 == buf + 6 + 16) {
|
||
|
tc_log_warn(__FILE__, "too much stuffing");
|
||
|
buf = tmp2;
|
||
|
break;
|
||
|
}
|
||
|
if ((*tmp1 & 0xc0) == 0x40)
|
||
|
tmp1 += 2;
|
||
|
tmp1 += mpeg1_skip_table [*tmp1 >> 4];
|
||
|
}
|
||
|
|
||
|
aid = *tmp1;
|
||
|
|
||
|
//-------------
|
||
|
//
|
||
|
//subtitle
|
||
|
//
|
||
|
//-------------
|
||
|
|
||
|
if((aid >= 0x20) && (aid <= 0x3F)) {
|
||
|
|
||
|
num=aid-0x20;
|
||
|
|
||
|
if(!(attr[num] & PACKAGE_SUBTITLE)) {
|
||
|
|
||
|
if(!track[num]) {
|
||
|
++ipipe->probe_info->num_tracks;
|
||
|
track[num]=1;
|
||
|
ipipe->probe_info->track[num].tid=num;
|
||
|
}
|
||
|
|
||
|
if(!(ipipe->probe_info->track[num].attribute &
|
||
|
PACKAGE_SUBTITLE)&& initial_sync) {
|
||
|
ipipe->probe_info->track[num].attribute |= PACKAGE_SUBTITLE;
|
||
|
|
||
|
// get pts time stamp:
|
||
|
ac_memcpy(scan_buf, &buf[6], 16);
|
||
|
has_pts_dts=get_pts_dts(scan_buf, &i_pts, &i_dts);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//-------------
|
||
|
//
|
||
|
//AC3 audio
|
||
|
//
|
||
|
//-------------
|
||
|
|
||
|
if(((aid >= 0x80 && aid <= 0x88)) || (aid>=0x90 && aid<=0x9f)) {
|
||
|
num=aid-0x80;
|
||
|
|
||
|
if(!(attr[num] & PACKAGE_AUDIO_AC3) && initial_sync) {
|
||
|
|
||
|
if(!track[num]) {
|
||
|
++ipipe->probe_info->num_tracks;
|
||
|
track[num]=1;
|
||
|
ipipe->probe_info->track[num].tid=num;
|
||
|
}
|
||
|
|
||
|
if(!(ipipe->probe_info->track[num].attribute &
|
||
|
PACKAGE_AUDIO_AC3)) {
|
||
|
|
||
|
tmp1 +=4;
|
||
|
|
||
|
//need to scan payload for more AC3 audio info
|
||
|
ret = buf_probe_ac3(tmp1, tmp2-tmp1, &ipipe->probe_info->track[num]);
|
||
|
if(ret==0) {
|
||
|
ipipe->probe_info->track[num].attribute |= PACKAGE_AUDIO_AC3;
|
||
|
ac_memcpy(scan_buf, &buf[6], 16);
|
||
|
has_pts_dts=get_pts_dts(scan_buf, &i_pts, &i_dts);
|
||
|
ipipe->probe_info->track[num].pts_start=(double) i_pts/90000.;
|
||
|
has_audio=1;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//-------------
|
||
|
//
|
||
|
// DTS audio
|
||
|
//
|
||
|
//-------------
|
||
|
|
||
|
if((aid >= 0x89) && (aid <= 0x8f)) {
|
||
|
num=aid-0x80;
|
||
|
|
||
|
if(!(attr[num] & PACKAGE_AUDIO_DTS) && initial_sync) {
|
||
|
|
||
|
if(!track[num]) {
|
||
|
++ipipe->probe_info->num_tracks;
|
||
|
track[num]=1;
|
||
|
ipipe->probe_info->track[num].tid=num;
|
||
|
}
|
||
|
|
||
|
if(!(ipipe->probe_info->track[num].attribute &
|
||
|
PACKAGE_AUDIO_DTS)) {
|
||
|
|
||
|
tmp1+=4;
|
||
|
|
||
|
//need to scan payload for more DTS audio info
|
||
|
ipipe->probe_info->track[num].attribute |= PACKAGE_AUDIO_DTS;
|
||
|
buf_probe_dts(tmp1, tmp2-tmp1, &ipipe->probe_info->track[num]);
|
||
|
|
||
|
ac_memcpy(scan_buf, &buf[6], 16);
|
||
|
has_pts_dts=get_pts_dts(scan_buf, &i_pts, &i_dts);
|
||
|
ipipe->probe_info->track[num].pts_start=(double) i_pts/90000.;
|
||
|
has_audio=1;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
//-------------
|
||
|
//
|
||
|
//AC3 audio
|
||
|
//
|
||
|
//-------------
|
||
|
|
||
|
if((aid >= 0x80) && (aid <= 0x88)) {
|
||
|
num=aid-0x80;
|
||
|
|
||
|
if(!(attr[num] & PACKAGE_AUDIO_AC3) && initial_sync) {
|
||
|
|
||
|
if(!track[num]) {
|
||
|
++ipipe->probe_info->num_tracks;
|
||
|
track[num]=1;
|
||
|
ipipe->probe_info->track[num].tid=num;
|
||
|
}
|
||
|
|
||
|
if(!(ipipe->probe_info->track[num].attribute &
|
||
|
PACKAGE_AUDIO_AC3)) {
|
||
|
|
||
|
tmp1 +=4;
|
||
|
|
||
|
//need to scan payload for more AC3 audio info
|
||
|
ret = buf_probe_ac3(tmp1, tmp2-tmp1, &ipipe->probe_info->track[num]);
|
||
|
if(ret==0) {
|
||
|
ipipe->probe_info->track[num].attribute |= PACKAGE_AUDIO_AC3;
|
||
|
ac_memcpy(scan_buf, &buf[6], 16);
|
||
|
has_pts_dts=get_pts_dts(scan_buf, &i_pts, &i_dts);
|
||
|
ipipe->probe_info->track[num].pts_start=(double) i_pts/90000.;
|
||
|
has_audio=1;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//-------------
|
||
|
//
|
||
|
//LPCM audio
|
||
|
//
|
||
|
//-------------
|
||
|
|
||
|
if((aid >= 0xA0) && (aid <= 0xBF)) {
|
||
|
num=aid-0xA0;
|
||
|
|
||
|
if(!(attr[num] & PACKAGE_AUDIO_PCM) && initial_sync) {
|
||
|
|
||
|
if(!track[num]) {
|
||
|
++ipipe->probe_info->num_tracks;
|
||
|
track[num]=1;
|
||
|
ipipe->probe_info->track[num].tid=num;
|
||
|
}
|
||
|
|
||
|
if(!(ipipe->probe_info->track[num].attribute &
|
||
|
PACKAGE_AUDIO_PCM)) {
|
||
|
|
||
|
tmp1 += 4;
|
||
|
|
||
|
ipipe->probe_info->track[num].attribute |= PACKAGE_AUDIO_PCM;
|
||
|
|
||
|
switch ((tmp1[1] >> 4) & 3) {
|
||
|
case 0: ipipe->probe_info->track[num].samplerate = 48000;
|
||
|
break;
|
||
|
case 1: ipipe->probe_info->track[num].samplerate = 96000;
|
||
|
break;
|
||
|
case 2: ipipe->probe_info->track[num].samplerate = 44100;
|
||
|
break;
|
||
|
case 3: ipipe->probe_info->track[num].samplerate = 32000;
|
||
|
break;
|
||
|
}
|
||
|
switch ((tmp1[1] >> 6) & 3) {
|
||
|
case 0: ipipe->probe_info->track[num].bits = 16;
|
||
|
break;
|
||
|
case 1: ipipe->probe_info->track[num].bits = 20;
|
||
|
break;
|
||
|
case 2: ipipe->probe_info->track[num].bits = 24;
|
||
|
break;
|
||
|
default: tc_log_error(__FILE__, "unknown LPCM quantization");
|
||
|
import_exit (1);
|
||
|
}
|
||
|
ipipe->probe_info->track[num].chan = 1 + (tmp1[1] & 7);
|
||
|
ipipe->probe_info->track[num].bitrate
|
||
|
= ipipe->probe_info->track[num].samplerate
|
||
|
* ipipe->probe_info->track[num].bits
|
||
|
* ipipe->probe_info->track[num].chan / 1000;
|
||
|
ipipe->probe_info->track[num].format=CODEC_LPCM;
|
||
|
|
||
|
ac_memcpy(scan_buf, &buf[6], 16);
|
||
|
has_pts_dts=get_pts_dts(scan_buf, &i_pts, &i_dts);
|
||
|
ipipe->probe_info->track[num].pts_start=(double) i_pts/90000.;
|
||
|
has_audio=1;
|
||
|
//ipipe->probe_info->track[num].pts_start=pack_ppp;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//-------------
|
||
|
//
|
||
|
//VAG audio
|
||
|
//
|
||
|
//-------------
|
||
|
|
||
|
if(aid == 0xFF && memcmp(tmp1+4,"SShd",4) == 0) {
|
||
|
num=0;
|
||
|
|
||
|
if(!(attr[num] & PACKAGE_AUDIO_VAG) && initial_sync) {
|
||
|
|
||
|
if(!track[num]) {
|
||
|
++ipipe->probe_info->num_tracks;
|
||
|
track[num]=1;
|
||
|
ipipe->probe_info->track[num].tid=num;
|
||
|
}
|
||
|
|
||
|
if(!(ipipe->probe_info->track[num].attribute &
|
||
|
PACKAGE_AUDIO_VAG)) {
|
||
|
|
||
|
tmp1 += 4; // skip MPEG data
|
||
|
tmp1 += 4; // skip "SShd" header tag
|
||
|
tmp1 += 4; // skip file (data+header) size (int32_le)
|
||
|
ipipe->probe_info->track[num].bits = *tmp1;
|
||
|
tmp1 += 4;
|
||
|
ipipe->probe_info->track[num].samplerate = tmp1[0]|tmp1[1]<<8;
|
||
|
tmp1 += 4;
|
||
|
ipipe->probe_info->track[num].chan = *tmp1;
|
||
|
tmp1 += 4;
|
||
|
// next 4 bytes are stereo quantization size
|
||
|
// next 8 bytes are unused?
|
||
|
// next 8 bytes are data block header "SSbd" and int32_le size
|
||
|
|
||
|
ipipe->probe_info->track[num].attribute |= PACKAGE_AUDIO_VAG;
|
||
|
ipipe->probe_info->track[num].bitrate
|
||
|
= ipipe->probe_info->track[num].samplerate
|
||
|
* ipipe->probe_info->track[num].chan
|
||
|
* 4 /* bits per sample, encoded */
|
||
|
* 16 / 14 /* overhead ratio */
|
||
|
/ 1000;
|
||
|
ipipe->probe_info->track[num].format = CODEC_VAG;
|
||
|
|
||
|
ac_memcpy(scan_buf, &buf[6], 16);
|
||
|
has_pts_dts=get_pts_dts(scan_buf, &i_pts, &i_dts);
|
||
|
ipipe->probe_info->track[num].pts_start=(double) i_pts/90000.;
|
||
|
has_audio=1;
|
||
|
//ipipe->probe_info->track[num].pts_start=pack_ppp;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
buf = tmp2;
|
||
|
|
||
|
break;
|
||
|
|
||
|
|
||
|
//------------------------
|
||
|
//
|
||
|
// MPEG audio
|
||
|
//
|
||
|
//------------------------
|
||
|
|
||
|
case 0xc0:
|
||
|
case 0xc1:
|
||
|
case 0xc2:
|
||
|
case 0xc3:
|
||
|
case 0xc4:
|
||
|
case 0xc5:
|
||
|
case 0xc6:
|
||
|
case 0xc7:
|
||
|
case 0xc8:
|
||
|
case 0xc9:
|
||
|
case 0xca:
|
||
|
case 0xcb:
|
||
|
case 0xcc:
|
||
|
case 0xcd:
|
||
|
case 0xce:
|
||
|
case 0xcf:
|
||
|
case 0xd0:
|
||
|
case 0xd1:
|
||
|
case 0xd2:
|
||
|
case 0xd3:
|
||
|
case 0xd4:
|
||
|
case 0xd5:
|
||
|
case 0xd6:
|
||
|
case 0xd7:
|
||
|
case 0xd8:
|
||
|
case 0xd9:
|
||
|
case 0xda:
|
||
|
case 0xdb:
|
||
|
case 0xdc:
|
||
|
case 0xdd:
|
||
|
case 0xde:
|
||
|
case 0xdf:
|
||
|
|
||
|
++stream[id];
|
||
|
|
||
|
tmp2 = buf + 6 + (buf[4] << 8) + buf[5];
|
||
|
if (tmp2 > end)
|
||
|
goto copy;
|
||
|
if ((buf[6] & 0xc0) == 0x80) /* mpeg2 */
|
||
|
tmp1 = buf + 9 + buf[8];
|
||
|
else { /* mpeg1 */
|
||
|
for (tmp1 = buf + 6; *tmp1 == 0xff; tmp1++)
|
||
|
if (tmp1 == buf + 6 + 16) {
|
||
|
tc_log_warn(__FILE__, "too much stuffing");
|
||
|
buf = tmp2;
|
||
|
break;
|
||
|
}
|
||
|
if ((*tmp1 & 0xc0) == 0x40)
|
||
|
tmp1 += 2;
|
||
|
tmp1 += mpeg1_skip_table [*tmp1 >> 4];
|
||
|
}
|
||
|
|
||
|
//add found track
|
||
|
//need to scan payload for more MPEG audio info
|
||
|
|
||
|
num=(buf[3] & 0xff) - 0xc0;
|
||
|
|
||
|
if(num >= 0 && !track[num] && num<TC_MAX_AUD_TRACKS && initial_sync) {
|
||
|
|
||
|
++ipipe->probe_info->num_tracks;
|
||
|
|
||
|
#ifdef HAVE_LAME
|
||
|
//need to scan payload for more MPEG audio info
|
||
|
if(end-buf>0) buf_probe_mp3(buf, end-buf, &ipipe->probe_info->track[num]);
|
||
|
#else
|
||
|
//all we know for now
|
||
|
ipipe->probe_info->track[num].format=CODEC_MP3;
|
||
|
ipipe->probe_info->track[num].tid=num;
|
||
|
#endif
|
||
|
|
||
|
ac_memcpy(scan_buf, &buf[6], 16);
|
||
|
has_pts_dts=get_pts_dts(scan_buf, &i_pts, &i_dts);
|
||
|
|
||
|
if(has_pts_dts) {
|
||
|
ipipe->probe_info->track[num].pts_start=(double) i_pts/90000.;
|
||
|
track[num]=1;
|
||
|
}
|
||
|
|
||
|
has_audio=1;
|
||
|
}
|
||
|
|
||
|
buf = tmp2;
|
||
|
break;
|
||
|
|
||
|
case 0xb3:
|
||
|
|
||
|
//MPEG video ES
|
||
|
probe_sequence(&buf[4], ipipe->probe_info);
|
||
|
|
||
|
ipipe->probe_info->codec=TC_CODEC_MPEG;
|
||
|
if ((buf[6] & 0xc0) == 0x80) ipipe->probe_info->codec=TC_CODEC_MPEG2;
|
||
|
|
||
|
return;
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
if (buf[3] < 0xb9) {
|
||
|
tc_log_warn(__FILE__, "looks like an elementary stream - not program stream");
|
||
|
ipipe->probe_info->codec=TC_CODEC_MPEG;
|
||
|
if ((buf[6] & 0xc0) == 0x80) ipipe->probe_info->codec=TC_CODEC_MPEG2;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
/* skip */
|
||
|
|
||
|
tmp1 = buf + 6 + (buf[4] << 8) + buf[5];
|
||
|
if (tmp1 > end)
|
||
|
goto copy;
|
||
|
buf = tmp1;
|
||
|
break;
|
||
|
|
||
|
} //start code selection
|
||
|
} //scan buffer
|
||
|
|
||
|
if (buf < end) {
|
||
|
copy:
|
||
|
/* we only pass here for mpeg1 ps streams */
|
||
|
memmove (buffer, buf, end - buf);
|
||
|
}
|
||
|
buf = buffer + (end - buf);
|
||
|
|
||
|
} while (end == buffer + BUFFER_SIZE);
|
||
|
|
||
|
adjust_info(ipipe);
|
||
|
return;
|
||
|
}
|