ac3strm_in.cpp

来自「Motion JPEG编解码器源代码」· C++ 代码 · 共 479 行

CPP
479
字号
/* *  ac3strm_in.c: AC3 Audio strem class members handling scanning and *  buffering raw input stream. * *  Copyright (C) 2001 Andrew Stevens <andrew.stevens@philips.com> *  Copyright (C) 2000,2001 Brent Byeler for original header-structure *                          parsing code. * * *  This program is free software; you can redistribute it and/or *  modify it under the terms of version 2 of the GNU General Public License *  as published by the Free Software Foundation. * *  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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA. */#include <config.h>#include <math.h>#include <stdlib.h>#include "audiostrm.hpp"#include "interact.hpp"#include "multiplexor.hpp"//#define DEBUG_AC3_HEADERS#define AC3_SYNCWORD            0x0b77#define AC3_PACKET_SAMPLES      1536const unsigned int AC3Stream::default_buffer_size = 16*1024;/// table for the available AC3 bitratesstatic const unsigned int ac3_bitrate_index[32] ={ 32,40,48,56,64,80,96,112,128,160,192,  224,256,320,384,448,512,576,640,  0,0,0,0,0,0,0,0,0,0,0,0,0};static const unsigned int ac3_frame_size[3][32] ={    { 64,80,96,112,128,160,192,224,256,320,384,      448,512,640,768,896,1024, 1152,1280,      0,0,0,0,0,0,0,0,0,0,0,0,0    },    { 69,87,104,121,139,174,208,243,278,348,417,      487,557,696,835,975,1114, 1253,1393,          0,0,0,0,0,0,0,0,0,0,0,0,0    },    { 96,120,144,168,192,240,288,336,384,480,576,      672,768,960,1152,1344, 1536,1728,1920,      0,0,0,0,0,0,0,0,0,0,0,0,0    }}; /// table for the available AC3 frequenciesstatic const unsigned int ac3_frequency[4] = { 48000, 44100, 32000, 0};AC3Stream::AC3Stream(IBitStream &ibs, Multiplexor &into) : 	AudioStream( ibs, into ){num_frames = 0;}bool AC3Stream::Probe(IBitStream &bs ){    return bs.GetBits(16) == AC3_SYNCWORD;}/************************************************************************* * * Reads initial stream parameters and displays feedback banner to users * @param stream_num AC3 substream ID *************************************************************************/void  AC3Stream::DisplayAc3HeaderInfo(){        /* Some stuff to generate frame-header information */        printf( "bsid         = %d\n", bs.GetBits(5) );        printf( "bsmode       = 0x%1x\n", bs.GetBits(3) );         int acmode = bs.GetBits(3);        int nfchans = 0;        switch( acmode )        {        case 0x0 :            nfchans = 2; break;        case 0x1 :            nfchans = 1; break;        case 0x2 :            nfchans = 2; break;        case 0x3 :        case 0x4 :            nfchans = 3; break;        case 0x5 :        case 0x6 :            nfchans = 4; break;        case 0x7 :            nfchans = 5; break;        }        printf( "acmode       = 0x%1x (%d channels)\n", acmode, nfchans );         if( (acmode & 0x1) && (acmode != 1 ) )            printf( "cmixlev  = %d\n", bs.GetBits(2) );         if( (acmode & 0x4) )            printf( "smixlev  = %d\n", bs.GetBits(2) );         if( acmode == 2 )             printf( "dsurr    = %d\n", bs.GetBits(2) );         printf( "lfeon        = %d\n", bs.GetBits(1) );         printf( "dialnorm     = %02d\n", bs.GetBits(5) );         int compre = bs.GetBits(1);        printf( "compre       = %d\n", compre );         if( compre )            printf( "compr    = %02d\n", bs.GetBits(8) );         int langcode = bs.GetBits(1);        printf( "langcode     = %d\n", langcode );         if( langcode )            printf( "langcod  = 0x%02x\n", bs.GetBits(8) );         int audprodie =  bs.GetBits(1);        printf( "audprodie    = %d\n", audprodie );        if( audprodie )        {            printf( "mixlevel = 0x%02x\n", bs.GetBits(5) );            printf( "roomtyp  = 0x%02x\n", bs.GetBits(2) );        }        if( acmode == 0 )        {            printf( "Skipping 1+1 mode parameters\n" );            bs.GetBits(5+1+8+1+8);            if( bs.GetBits(1) )                bs.GetBits(7);        }        printf( "Copyright  = %d\n", bs.GetBits(1) );         printf( "Original   = %d\n", bs.GetBits(1) );         int timecod1e = bs.GetBits(1);        if( timecod1e )        {            printf( "timecod1 = 0x%03x\n", bs.GetBits(14) );        }        int timecod2e = bs.GetBits(1);        if( timecod2e )        {            printf( "timecod2 = 0x%03x\n", bs.GetBits(14) );        }        int addbsie = bs.GetBits(1);        if( addbsie )        {            printf( "addbsil  = %02x\n", bs.GetBits(6) );        }                // FROM This point on we're actually right into the actual audio block        printf( "Audio block header...\n" );        printf( "blksw  [ch] = %02x\n", bs.GetBits(nfchans) );        printf( "dithflg[ch] = %02x\n", bs.GetBits(nfchans) );        int dynrnge = bs.GetBits(1);        printf( "Dynrange    = %d\n", bs.GetBits(1) );         if( dynrnge )        {            printf( "dynrng    = %02x\n", bs.GetBits(8) );        }        if( acmode == 0 && bs.GetBits(1) )        {            printf( "dynrng2   = %02x\n", bs.GetBits(8) );        }        int cplstre = bs.GetBits(1);        printf( "cplstre     = %d\n", cplstre );         int cplinu = 0;        if( cplstre )        {            cplinu = bs.GetBits(1);            printf( "cplinu    = %d\n", cplinu );            if( cplinu )            {                printf( "Skipping cplinu=1 info...\n");                bs.GetBits(nfchans);                if( acmode == 2 )                    bs.GetBits(1);                int cplbegf = bs.GetBits(4);                int cplendf = bs.GetBits(4);                bs.GetBits(3+cplbegf-cplendf);            }        }        if( cplinu )        {            printf( "Warning: no parser for coupling co-ordinates mess\n");            return;        }        if( acmode == 2 )        {            int rmatstr = bs.GetBits(1);            printf( "rmatstr = %d\n", rmatstr );            printf( "Warning: no parser for rematrixing...\n" );        }        }void AC3Stream::Init ( const int _stream_num){    unsigned int framesize_code;    stream_num = _stream_num;	MuxStream::Init( PRIVATE_STR_1, 					 1,  // Buffer scale					 default_buffer_size,					 false,					 muxinto.buffers_in_audio,					 muxinto.always_buffers_in_audio		);    mjpeg_info ("Scanning for header info: AC3 Audio stream %02x (%s)",                stream_num,                bs.StreamName()                );	AU_start = bs.bitcount();    if (bs.GetBits(16)==AC3_SYNCWORD)    {		num_syncword++;        bs.GetBits(16);         // CRC field        frequency = bs.GetBits(2);  // Sample rate code        framesize_code = bs.GetBits(6); // Frame size code        framesize = ac3_frame_size[frequency][framesize_code>>1];        framesize =             (framesize_code&1) && frequency == 1 ?            (framesize + 1) << 1:            (framesize <<1);                    header_skip = 5;        // Initially skipped past  5 bytes of header 	num_frames++;        access_unit.start = AU_start;	access_unit.length = framesize;        mjpeg_info( "AC3 frame size = %d", framesize );        bit_rate = ac3_bitrate_index[framesize_code>>1];		samples_per_second = ac3_frequency[frequency];		/* Presentation time-stamping  */		access_unit.PTS = static_cast<clockticks>(decoding_order) * 			static_cast<clockticks>(AC3_PACKET_SAMPLES) * 			static_cast<clockticks>(CLOCKS)	/ samples_per_second;		access_unit.DTS = access_unit.PTS;		access_unit.dorder = decoding_order;		++decoding_order;		aunits.Append( access_unit );    } else    {		mjpeg_error ( "Invalid AC3 Audio stream header.");		exit (1);    }	OutputHdrInfo();}/// @returns the current bitrateunsigned int AC3Stream::NominalBitRate(){ 	return bit_rate*1024;}/// Prefills the internal buffer for output multiplexing./// @param frames_to_buffer the number of audio frames to read aheadvoid AC3Stream::FillAUbuffer(unsigned int frames_to_buffer ){	unsigned int framesize_code;	last_buffered_AU += frames_to_buffer;	mjpeg_debug( "Scanning %d AC3 audio frames to frame %d", 				 frames_to_buffer, last_buffered_AU );    int skip;	while( !bs.eos()            && decoding_order < last_buffered_AU            && !muxinto.AfterMaxPTS(access_unit.PTS)        )	{		skip=access_unit.length-header_skip;         bs.SeekFwdBits(skip);		prev_offset = AU_start;		AU_start = bs.bitcount();        if( AU_start - prev_offset != access_unit.length*8 )        {            mjpeg_warn( "Discarding incomplete final frame AC3 stream %d!",                       stream_num);            aunits.DropLast();            --decoding_order;            break;        }		/* Check we have reached the end of have  another catenated 		   stream to process before finishing ... */		if ( (syncword = bs.GetBits(16))!=AC3_SYNCWORD )		{			if( !bs.eos()   )			{				mjpeg_error_exit1( "Can't find next AC3 frame: @ %lld we have %04x - broken bit-stream?", AU_start/8, syncword );            }            break;		}        bs.GetBits(16);         // CRC field        bs.GetBits(2);          // Sample rate code TOOD: check for change!        framesize_code = bs.GetBits(6);        framesize = ac3_frame_size[frequency][framesize_code>>1];        framesize =             (framesize_code&1) && frequency == 1 ?            (framesize + 1) << 1:            (framesize <<1);		access_unit.start = AU_start;		access_unit.length = framesize;		access_unit.PTS = static_cast<clockticks>(decoding_order) * 			static_cast<clockticks>(AC3_PACKET_SAMPLES) * 			static_cast<clockticks>(CLOCKS)	/ samples_per_second;;		access_unit.DTS = access_unit.PTS;		access_unit.dorder = decoding_order;		decoding_order++;		aunits.Append( access_unit );		num_frames++;				num_syncword++;		if (num_syncword >= old_frames+10 )		{			mjpeg_debug ("Got %d frame headers.", num_syncword);			old_frames=num_syncword;		}            }	last_buffered_AU = decoding_order;	eoscan = bs.eos() || muxinto.AfterMaxPTS(access_unit.PTS);}/// Closes the AC3 stream and prints some statistics.void AC3Stream::Close(){    stream_length = AU_start >> 3;	mjpeg_info ("AUDIO_STATISTICS: %02x", stream_id);     mjpeg_info ("Audio stream length %lld bytes.", stream_length);    mjpeg_info   ("Frames         : %8u",  num_frames);}/*************************************************************************	OutputAudioInfo	gibt gesammelte Informationen zu den Audio Access Units aus.	Prints information on audio access units*************************************************************************/void AC3Stream::OutputHdrInfo (){	mjpeg_info("AC3 AUDIO STREAM:");    mjpeg_info ("Bit rate       : %8u bytes/sec (%3u kbit/sec)",				bit_rate*128, bit_rate);    if (frequency == 3)		mjpeg_info ("Frequency      : reserved");    else		mjpeg_info ("Frequency      :     %d Hz",				ac3_frequency[frequency]);}/**Reads the bytes neccessary to complete the current packet payload. @param to_read number of bytes to read@param dst byte buffer pointer to read to @returns the number of bytes read */unsigned int AC3Stream::ReadPacketPayload(uint8_t *dst, unsigned int to_read){    bitcount_t read_start = bs.GetBytePos();    // Remember to change StreamHeaderLen if you write a different    // length re-using this code...    unsigned int bytes_read = bs.GetBytes( dst+4, to_read-4 );    assert( bytes_read > 0 );   // Should never try to read nothing    bs.Flush( read_start );	clockticks   decode_time;    unsigned int first_header =         (new_au_next_sec || au_unsent > bytes_read )        ? 0         : au_unsent;    // BUG BUG BUG: how do we set the 1st header pointer if we have    // the *middle* part of a large frame?    assert( first_header+2 <= to_read );    unsigned int syncwords = 0;    unsigned int bytes_muxed = bytes_read;  	if (bytes_muxed == 0 || MuxCompleted() )    {		goto completion;    }	/* Work through what's left of the current AU and the following AU's	   updating the info until we reach a point where an AU had to be	   split between packets.	   NOTE: It *is* possible for this loop to iterate. 	   The DTS/PTS field for the packet in this case would have been	   given the that for the first AU to start in the packet.	*/	decode_time = RequiredDTS();	while (au_unsent < bytes_muxed)	{	          // BUG BUG BUG: if we ever had odd payload / packet size we might        // split an AC3 frame in the middle of the syncword!        assert( bytes_muxed > 1 );		bufmodel.Queued(au_unsent, decode_time);		bytes_muxed -= au_unsent;        if( new_au_next_sec )            ++syncwords;		if( !NextAU() )        {            goto completion;        }		new_au_next_sec = true;		decode_time = RequiredDTS();	};	// We've now reached a point where the current AU overran or	// fitted exactly.  We need to distinguish the latter case	// so we can record whether the next packet starts with an	// existing AU or not - info we need to decide what PTS/DTS	// info to write at the start of the next packet.		if (au_unsent > bytes_muxed)	{        if( new_au_next_sec )            ++syncwords;		bufmodel.Queued( bytes_muxed, decode_time);		au_unsent -= bytes_muxed;		new_au_next_sec = false;	} 	else //  if (au_unsent == bytes_muxed)	{		bufmodel.Queued(bytes_muxed, decode_time);        if( new_au_next_sec )            ++syncwords;        new_au_next_sec = NextAU();	}	   completion:    // Generate the AC3 header...    // Note the index counts from the low byte of the offset so    // the smallest value is 1!    dst[0] = AC3_SUB_STR_0 + stream_num;    dst[1] = syncwords;    dst[2] = (first_header+1)>>8;    dst[3] = (first_header+1)&0xff;	return bytes_read+4;}/*  * Local variables: *  c-file-style: "stroustrup" *  tab-width: 4 *  indent-tabs-mode: nil * End: */

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?