diff options
author | Jean-Marc Valin <jmvalin@jmvalin.ca> | 2014-07-30 21:41:28 +0400 |
---|---|---|
committer | Jean-Marc Valin <jmvalin@jmvalin.ca> | 2014-07-30 21:47:16 +0400 |
commit | e070300a341a605b3ed08baa642b661d2587a841 (patch) | |
tree | 41485385fb650984388f0be97501decff617827d | |
parent | 1e87fea32698ac3070ebf092d2ca08feae57373f (diff) | |
parent | bb4b6885a139644cf3ac14e7deda9f633ec2d93c (diff) |
Merge remote-tracking branch 'origin/master' into derf_rtp_edits
Conflicts:
doc/draft-ietf-payload-rtp-opus.xml
-rw-r--r-- | doc/draft-ietf-payload-rtp-opus.xml | 29 | ||||
-rw-r--r-- | silk/CNG.c | 21 | ||||
-rw-r--r-- | silk/decode_frame.c | 10 | ||||
-rw-r--r-- | silk/fixed/burg_modified_FIX.c | 28 | ||||
-rw-r--r-- | src/opus_multistream_encoder.c | 34 | ||||
-rw-r--r-- | win32/genversion.bat | 12 |
6 files changed, 88 insertions, 46 deletions
diff --git a/doc/draft-ietf-payload-rtp-opus.xml b/doc/draft-ietf-payload-rtp-opus.xml index 412ce0fc..f4f99390 100644 --- a/doc/draft-ietf-payload-rtp-opus.xml +++ b/doc/draft-ietf-payload-rtp-opus.xml @@ -1,6 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE rfc SYSTEM "rfc2629.dtd" [ <!ENTITY rfc2119 PUBLIC '' 'http://xml.resource.org/public/rfc/bibxml/reference.RFC.2119.xml'> +<!ENTITY rfc3389 PUBLIC '' 'http://xml.resource.org/public/rfc/bibxml/reference.RFC.3389.xml'> <!ENTITY rfc3550 PUBLIC '' 'http://xml.resource.org/public/rfc/bibxml/reference.RFC.3550.xml'> <!ENTITY rfc3711 PUBLIC '' 'http://xml.resource.org/public/rfc/bibxml/reference.RFC.3711.xml'> <!ENTITY rfc3551 PUBLIC '' 'http://xml.resource.org/public/rfc/bibxml/reference.RFC.3551.xml'> @@ -17,7 +18,7 @@ <!ENTITY nbsp " "> ]> - <rfc category="std" ipr="trust200902" docName="draft-ietf-payload-rtp-opus-01"> + <rfc category="std" ipr="trust200902" docName="draft-ietf-payload-rtp-opus-03"> <?xml-stylesheet type='text/xsl' href='rfc2629.xslt' ?> <?rfc strict="yes" ?> @@ -60,7 +61,7 @@ <organization>Mozilla</organization> <address> <postal> - <street>650 Castro Street</street> + <street>331 E. Evelyn Avenue</street> <city>Mountain View</city> <region>CA</region> <code>94041</code> @@ -70,7 +71,7 @@ </address> </author> - <date day='14' month='January' year='2014' /> + <date day='30' month='July' year='2014' /> <abstract> <t> @@ -247,14 +248,22 @@ the Opus encoder can use discontinuous transmission (DTX), where parts of the encoded signal that correspond to periods of silence in the input speech or audio signal - are not transmitted to the receiver. + are not transmitted to the receiver. A receiver can distinguish + between DTX and packet loss by looking for gaps in the sequence + number, as described by Section 4.1 + of <xref target="RFC3551"/>. </t> <t> On the receiving side, the non-transmitted parts will be handled by a frame loss concealment unit in the Opus decoder which generates a comfort noise signal to replace the non transmitted parts of the - speech or audio signal. + speech or audio signal. Use of <xref target="RFC3389"/> Comfort + Noise (CN) with Opus is discouraged. + The transmitter MUST drop whole frames only, + based on the size of the last transmitted frame, + to ensure successive RTP timestamps differ by a multiple of 120 and + to allow the receiver to use whole frames for concealment. </t> <t> @@ -347,8 +356,9 @@ therefore no padding is necessary. The payload MAY be padded by an integer number of octets according to <xref target="RFC3550"/>.</t> - <t>The marker bit (M) of the RTP header is used in accordance with - Section 4.1 of <xref target="RFC3551"/>.</t> + <t>The timestamp, sequence number, and marker bit (M) of the RTP header + are used in accordance with Section 4.1 + of <xref target="RFC3551"/>.</t> <t>The RTP payload type for Opus has not been assigned statically and is expected to be assigned dynamically.</t> @@ -738,8 +748,8 @@ <t>Example 2: 16000 Hz clock rate, maximum packet size of 40 ms, recommended packet size of 40 ms, maximum average bitrate of 20000 bps, - prefers to receive stereo but only plans to send mono, FEC is allowed, - DTX is not allowed</t> + prefers to receive stereo but only plans to send mono, FEC is desired, + DTX is not desired</t> <figure> <artwork> @@ -926,6 +936,7 @@ <back> <references title="Normative References"> &rfc2119; + &rfc3389; &rfc3550; &rfc3711; &rfc3551; @@ -34,7 +34,7 @@ POSSIBILITY OF SUCH DAMAGE. /* Generates excitation for CNG LPC synthesis */ static OPUS_INLINE void silk_CNG_exc( - opus_int32 residual_Q10[], /* O CNG residual signal Q10 */ + opus_int32 exc_Q10[], /* O CNG excitation signal Q10 */ opus_int32 exc_buf_Q14[], /* I Random samples buffer Q10 */ opus_int32 Gain_Q16, /* I Gain to apply */ opus_int length, /* I Length */ @@ -55,7 +55,7 @@ static OPUS_INLINE void silk_CNG_exc( idx = (opus_int)( silk_RSHIFT( seed, 24 ) & exc_mask ); silk_assert( idx >= 0 ); silk_assert( idx <= CNG_BUF_MASK_MAX ); - residual_Q10[ i ] = (opus_int16)silk_SAT16( silk_SMULWW( exc_buf_Q14[ idx ], Gain_Q16 >> 4 ) ); + exc_Q10[ i ] = (opus_int16)silk_SAT16( silk_SMULWW( exc_buf_Q14[ idx ], Gain_Q16 >> 4 ) ); } *rand_seed = seed; } @@ -85,7 +85,7 @@ void silk_CNG( ) { opus_int i, subfr; - opus_int32 sum_Q6, max_Gain_Q16; + opus_int32 sum_Q6, max_Gain_Q16, gain_Q16; opus_int16 A_Q12[ MAX_LPC_ORDER ]; silk_CNG_struct *psCNG = &psDec->sCNG; SAVE_STACK; @@ -125,11 +125,20 @@ void silk_CNG( /* Add CNG when packet is lost or during DTX */ if( psDec->lossCnt ) { VARDECL( opus_int32, CNG_sig_Q10 ); - ALLOC( CNG_sig_Q10, length + MAX_LPC_ORDER, opus_int32 ); /* Generate CNG excitation */ - silk_CNG_exc( CNG_sig_Q10 + MAX_LPC_ORDER, psCNG->CNG_exc_buf_Q14, psCNG->CNG_smth_Gain_Q16, length, &psCNG->rand_seed ); + gain_Q16 = silk_SMULWW( psDec->sPLC.randScale_Q14, psDec->sPLC.prevGain_Q16[1] ); + if( gain_Q16 >= (1 << 21) || psCNG->CNG_smth_Gain_Q16 > (1 << 23) ) { + gain_Q16 = silk_SMULTT( gain_Q16, gain_Q16 ); + gain_Q16 = silk_SUB_LSHIFT32(silk_SMULTT( psCNG->CNG_smth_Gain_Q16, psCNG->CNG_smth_Gain_Q16 ), gain_Q16, 5 ); + gain_Q16 = silk_LSHIFT32( silk_SQRT_APPROX( gain_Q16 ), 16 ); + } else { + gain_Q16 = silk_SMULWW( gain_Q16, gain_Q16 ); + gain_Q16 = silk_SUB_LSHIFT32(silk_SMULWW( psCNG->CNG_smth_Gain_Q16, psCNG->CNG_smth_Gain_Q16 ), gain_Q16, 5 ); + gain_Q16 = silk_LSHIFT32( silk_SQRT_APPROX( gain_Q16 ), 8 ); + } + silk_CNG_exc( CNG_sig_Q10 + MAX_LPC_ORDER, psCNG->CNG_exc_buf_Q14, gain_Q16, length, &psCNG->rand_seed ); /* Convert CNG NLSF to filter representation */ silk_NLSF2A( A_Q12, psCNG->CNG_smth_NLSF_Q15, psDec->LPC_order ); @@ -162,7 +171,7 @@ void silk_CNG( /* Update states */ CNG_sig_Q10[ MAX_LPC_ORDER + i ] = silk_ADD_LSHIFT( CNG_sig_Q10[ MAX_LPC_ORDER + i ], sum_Q6, 4 ); - frame[ i ] = silk_ADD_SAT16( frame[ i ], silk_RSHIFT_ROUND( sum_Q6, 6 ) ); + frame[ i ] = silk_ADD_SAT16( frame[ i ], silk_RSHIFT_ROUND( CNG_sig_Q10[ MAX_LPC_ORDER + i ], 10 ) ); } silk_memcpy( psCNG->CNG_synth_state, &CNG_sig_Q10[ length ], MAX_LPC_ORDER * sizeof( opus_int32 ) ); } else { diff --git a/silk/decode_frame.c b/silk/decode_frame.c index 37459a32..6a7cffbb 100644 --- a/silk/decode_frame.c +++ b/silk/decode_frame.c @@ -107,16 +107,16 @@ opus_int silk_decode_frame( silk_memmove( psDec->outBuf, &psDec->outBuf[ psDec->frame_length ], mv_len * sizeof(opus_int16) ); silk_memcpy( &psDec->outBuf[ mv_len ], pOut, psDec->frame_length * sizeof( opus_int16 ) ); - /****************************************************************/ - /* Ensure smooth connection of extrapolated and good frames */ - /****************************************************************/ - silk_PLC_glue_frames( psDec, pOut, L ); - /************************************************/ /* Comfort noise generation / estimation */ /************************************************/ silk_CNG( psDec, psDecCtrl, pOut, L ); + /****************************************************************/ + /* Ensure smooth connection of extrapolated and good frames */ + /****************************************************************/ + silk_PLC_glue_frames( psDec, pOut, L ); + /* Update some decoder state variables */ psDec->lagPrev = psDecCtrl->pitchL[ psDec->nb_subfr - 1 ]; diff --git a/silk/fixed/burg_modified_FIX.c b/silk/fixed/burg_modified_FIX.c index db348295..2a260775 100644 --- a/silk/fixed/burg_modified_FIX.c +++ b/silk/fixed/burg_modified_FIX.c @@ -54,7 +54,7 @@ void silk_burg_modified( int arch /* I Run-time architecture */ ) { - opus_int k, n, s, lz, rshifts, rshifts_extra, reached_max_gain; + opus_int k, n, s, lz, rshifts, reached_max_gain; opus_int32 C0, num, nrg, rc_Q31, invGain_Q30, Atmp_QA, Atmp1, tmp1, tmp2, x1, x2; const opus_int16 *x_ptr; opus_int32 C_first_row[ SILK_MAX_ORDER_LPC ]; @@ -63,27 +63,23 @@ void silk_burg_modified( opus_int32 CAf[ SILK_MAX_ORDER_LPC + 1 ]; opus_int32 CAb[ SILK_MAX_ORDER_LPC + 1 ]; opus_int32 xcorr[ SILK_MAX_ORDER_LPC ]; + opus_int64 C0_64; silk_assert( subfr_length * nb_subfr <= MAX_FRAME_SIZE ); /* Compute autocorrelations, added over subframes */ - silk_sum_sqr_shift( &C0, &rshifts, x, nb_subfr * subfr_length ); - if( rshifts > MAX_RSHIFTS ) { - C0 = silk_LSHIFT32( C0, rshifts - MAX_RSHIFTS ); - silk_assert( C0 > 0 ); - rshifts = MAX_RSHIFTS; + C0_64 = silk_inner_prod16_aligned_64( x, x, subfr_length*nb_subfr ); + lz = silk_CLZ64(C0_64); + rshifts = 32 + 1 + N_BITS_HEAD_ROOM - lz; + if (rshifts > MAX_RSHIFTS) rshifts = MAX_RSHIFTS; + if (rshifts < MIN_RSHIFTS) rshifts = MIN_RSHIFTS; + + if (rshifts > 0) { + C0 = (opus_int32)silk_RSHIFT64(C0_64, rshifts ); } else { - lz = silk_CLZ32( C0 ) - 1; - rshifts_extra = N_BITS_HEAD_ROOM - lz; - if( rshifts_extra > 0 ) { - rshifts_extra = silk_min( rshifts_extra, MAX_RSHIFTS - rshifts ); - C0 = silk_RSHIFT32( C0, rshifts_extra ); - } else { - rshifts_extra = silk_max( rshifts_extra, MIN_RSHIFTS - rshifts ); - C0 = silk_LSHIFT32( C0, -rshifts_extra ); - } - rshifts += rshifts_extra; + C0 = silk_LSHIFT32((opus_int32)C0_64, -rshifts ); } + CAb[ 0 ] = CAf[ 0 ] = C0 + silk_SMMUL( SILK_FIX_CONST( FIND_LPC_COND_FAC, 32 ), C0 ) + 1; /* Q(-rshifts) */ silk_memset( C_first_row, 0, SILK_MAX_ORDER_LPC * sizeof( opus_int32 ) ); if( rshifts > 0 ) { diff --git a/src/opus_multistream_encoder.c b/src/opus_multistream_encoder.c index 6e52a4db..aa464f59 100644 --- a/src/opus_multistream_encoder.c +++ b/src/opus_multistream_encoder.c @@ -591,7 +591,7 @@ OpusMSEncoder *opus_multistream_surround_encoder_create( return st; } -static void surround_rate_allocation( +static opus_int32 surround_rate_allocation( OpusMSEncoder *st, opus_int32 *rate, int frame_size @@ -605,6 +605,7 @@ static void surround_rate_allocation( int lfe_offset; int coupled_ratio; /* Q8 */ int lfe_ratio; /* Q8 */ + opus_int32 rate_sum=0; ptr = (char*)st + align(sizeof(OpusMSEncoder)); opus_encoder_ctl((OpusEncoder*)ptr, OPUS_GET_SAMPLE_RATE(&Fs)); @@ -660,7 +661,10 @@ static void surround_rate_allocation( rate[i] = stream_offset+channel_rate; else rate[i] = lfe_offset+(channel_rate*lfe_ratio>>8); + rate[i] = IMAX(rate[i], 500); + rate_sum += rate[i]; } + return rate_sum; } /* Max size in case the encoder decides to return three frames */ @@ -695,6 +699,8 @@ static int opus_multistream_encode_native opus_val32 *mem = NULL; opus_val32 *preemph_mem=NULL; int frame_size; + opus_int32 rate_sum; + opus_int32 smallest_packet; ALLOC_STACK; if (st->surround) @@ -738,6 +744,18 @@ static int opus_multistream_encode_native RESTORE_STACK; return OPUS_BAD_ARG; } + /* Estimate (slightly overestimating) of the smallest packet the encoder can produce. */ + if (50*frame_size <= Fs) + { + smallest_packet = st->layout.nb_streams*4; + } else { + smallest_packet = st->layout.nb_streams*4*50*frame_size/Fs; + } + if (max_data_bytes < smallest_packet) + { + RESTORE_STACK; + return OPUS_BAD_ARG; + } ALLOC(buf, 2*frame_size, opus_val16); coupled_size = opus_encoder_get_size(2); mono_size = opus_encoder_get_size(1); @@ -755,11 +773,19 @@ static int opus_multistream_encode_native } /* Compute bitrate allocation between streams (this could be a lot better) */ - surround_rate_allocation(st, bitrates, frame_size); + rate_sum = surround_rate_allocation(st, bitrates, frame_size); if (!vbr) - max_data_bytes = IMIN(max_data_bytes, 3*st->bitrate_bps/(3*8*Fs/frame_size)); - + { + if (st->bitrate_bps == OPUS_AUTO) + { + max_data_bytes = IMIN(max_data_bytes, 3*rate_sum/(3*8*Fs/frame_size)); + } else if (st->bitrate_bps != OPUS_BITRATE_MAX) + { + max_data_bytes = IMIN(max_data_bytes, IMAX(smallest_packet, + 3*st->bitrate_bps/(3*8*Fs/frame_size))); + } + } ptr = (char*)st + align(sizeof(OpusMSEncoder)); for (s=0;s<st->layout.nb_streams;s++) { diff --git a/win32/genversion.bat b/win32/genversion.bat index a9b9353a..cd1d4dce 100644 --- a/win32/genversion.bat +++ b/win32/genversion.bat @@ -23,10 +23,10 @@ set version=!version: =! :gotversion -set version_out=#define %2 "%version%" -set version_mk=%2 = "%version%" +set version_out=#define %~2 "%version%" +set version_mk=%~2 = "%version%" -echo %version_out%> "%1_temp" +echo %version_out%> "%~1_temp" if %version%==unknown goto :skipgenerate @@ -35,12 +35,12 @@ echo %version_mk%>> "%~dp0..\version.mk" :skipgenerate -echo n | comp "%1_temp" "%1" > NUL 2> NUL +echo n | comp "%~1_temp" "%~1" > NUL 2> NUL if not errorlevel 1 goto exit -copy /y "%1_temp" "%1" +copy /y "%~1_temp" "%~1" :exit -del "%1_temp" +del "%~1_temp" |