Ignore:
Timestamp:
Jun 5, 2008 10:50:40 AM (11 years ago)
Author:
nanang
Message:

Ticket #473:

  • fixed issue on Speex multiple frames (encoding: encoded bits concatenation & decoding: frames parsing)
  • updated pjmedia stream & codecs on encoding multiple frames
  • introduced bit_info in pjmedia_frame and jitter buffer
File:
1 edited

Legend:

Unmodified
Added
Removed
  • pjproject/trunk/pjmedia/src/pjmedia-codec/speex_codec.c

    r1965 r1983  
    161161        return PJMEDIA_CODEC_EFAILED; 
    162162 
    163     /* Set the quality */ 
    164     if (p->quality != -1) 
    165         speex_encoder_ctl(state, SPEEX_SET_QUALITY, &p->quality); 
     163    /* We have to get maximum bitrate, so let's set maximum quality */ 
     164    tmp = 10; 
     165    speex_encoder_ctl(state, SPEEX_SET_QUALITY, &tmp); 
    166166 
    167167    /* Sampling rate. */ 
     
    596596    id = spx->param_id; 
    597597 
    598     /* Only supports one frame per packet */ 
    599     PJ_ASSERT_RETURN(attr->setting.frm_per_pkt==1, PJ_EINVAL); 
    600  
    601598    /*  
    602599     * Create and initialize encoder.  
     
    688685    spx = (struct spx_private*) codec->codec_data; 
    689686 
    690     /* Only supports one frame per packet */ 
    691     PJ_ASSERT_RETURN(attr->setting.frm_per_pkt==1, PJ_EINVAL); 
    692  
    693687    /* VAD */ 
    694688    tmp = (attr->setting.vad != 0); 
     
    701695 
    702696    return PJ_SUCCESS; 
     697} 
     698 
     699#if 0 
     700#  define TRACE__(args)     PJ_LOG(5,args) 
     701#else 
     702#  define TRACE__(args) 
     703#endif 
     704 
     705#undef THIS_FUNC 
     706#define THIS_FUNC "speex_get_next_frame" 
     707 
     708#define NB_SUBMODES 16 
     709#define NB_SUBMODE_BITS 4 
     710 
     711#define SB_SUBMODES 8 
     712#define SB_SUBMODE_BITS 3 
     713 
     714/* This function will iterate frames & submodes in the Speex bits. 
     715 * Returns 0 if a frame found, otherwise returns -1. 
     716 */ 
     717int speex_get_next_frame(SpeexBits *bits) 
     718{ 
     719    static const int inband_skip_table[NB_SUBMODES] = 
     720       {1, 1, 4, 4, 4, 4, 4, 4, 8, 8, 16, 16, 32, 32, 64, 64 }; 
     721    static const int wb_skip_table[SB_SUBMODES] = 
     722       {SB_SUBMODE_BITS+1, 36, 112, 192, 352, -1, -1, -1}; 
     723 
     724    unsigned submode; 
     725    unsigned nb_count = 0; 
     726 
     727    while (speex_bits_remaining(bits) >= 5) { 
     728        unsigned wb_count = 0; 
     729        unsigned bit_ptr = bits->bitPtr; 
     730        unsigned char_ptr = bits->charPtr; 
     731 
     732        /* WB frame */ 
     733        while ((speex_bits_remaining(bits) >= 4) 
     734            && speex_bits_unpack_unsigned(bits, 1)) 
     735        { 
     736            int advance; 
     737 
     738            submode = speex_bits_unpack_unsigned(bits, 3); 
     739            advance = wb_skip_table[submode]; 
     740            if (advance < 0) { 
     741                TRACE__((THIS_FUNC, "Invalid mode encountered. " 
     742                         "The stream is corrupted.")); 
     743                return -1; 
     744            }  
     745            TRACE__((THIS_FUNC, "WB layer skipped: %d bits", advance)); 
     746            advance -= (SB_SUBMODE_BITS+1); 
     747            speex_bits_advance(bits, advance); 
     748 
     749            bit_ptr = bits->bitPtr; 
     750            char_ptr = bits->charPtr; 
     751 
     752            /* Consecutive subband frames may not exceed 2 frames */ 
     753            if (++wb_count > 2) 
     754                return -1; 
     755        } 
     756 
     757        /* End of bits, return the frame */ 
     758        if (speex_bits_remaining(bits) < 4) { 
     759            TRACE__((THIS_FUNC, "End of stream")); 
     760            return 0; 
     761        } 
     762 
     763        /* Stop iteration, return the frame */ 
     764        if (nb_count > 0) { 
     765            bits->bitPtr = bit_ptr; 
     766            bits->charPtr = char_ptr; 
     767            return 0; 
     768        } 
     769 
     770        /* Get control bits */ 
     771        submode = speex_bits_unpack_unsigned(bits, 4); 
     772        TRACE__((THIS_FUNC, "Control bits: %d at %d",  
     773                 submode, bits->charPtr*8+bits->bitPtr)); 
     774 
     775        if (submode == 15) { 
     776            TRACE__((THIS_FUNC, "Found submode: terminator")); 
     777            return 0; 
     778        } else if (submode == 14) { 
     779            /* in-band signal; next 4 bits contain signal id */ 
     780            submode = speex_bits_unpack_unsigned(bits, 4); 
     781            TRACE__((THIS_FUNC, "Found submode: in-band %d bits",  
     782                     inband_skip_table[submode])); 
     783            speex_bits_advance(bits, inband_skip_table[submode]); 
     784        } else if (submode == 13) { 
     785            /* user in-band; next 5 bits contain msg len */ 
     786            submode = speex_bits_unpack_unsigned(bits, 5); 
     787            TRACE__((THIS_FUNC, "Found submode: user-band %d bytes", submode)); 
     788            speex_bits_advance(bits, submode * 8); 
     789        } else if (submode > 8) { 
     790            TRACE__((THIS_FUNC, "Unknown sub-mode %d", submode)); 
     791            return 0; 
     792        } else { 
     793            /* NB frame */ 
     794            unsigned int advance = submode; 
     795            speex_mode_query(&speex_nb_mode, SPEEX_SUBMODE_BITS_PER_FRAME, &advance); 
     796            if (advance < 0) { 
     797                TRACE__((THIS_FUNC, "Invalid mode encountered. " 
     798                         "The stream is corrupted.")); 
     799                return -1; 
     800            } 
     801            TRACE__((THIS_FUNC, "Submode %d: %d bits", submode, advance)); 
     802            advance -= (NB_SUBMODE_BITS+1); 
     803            speex_bits_advance(bits, advance); 
     804 
     805            ++nb_count; 
     806        } 
     807    } 
     808 
     809    return 0; 
    703810} 
    704811 
     
    714821                                     pjmedia_frame frames[]) 
    715822{ 
    716     struct spx_private *spx; 
    717     unsigned frame_size, samples_per_frame; 
    718     unsigned count; 
    719  
    720     spx = (struct spx_private*) codec->codec_data; 
    721  
    722     frame_size = spx_factory.speex_param[spx->param_id].framesize; 
    723     samples_per_frame = spx_factory.speex_param[spx->param_id].samples_per_frame; 
    724  
    725     /* Don't really know how to do this... */ 
    726     count = 0; 
    727     while (pkt_size >= frame_size && count < *frame_cnt) { 
    728         frames[count].buf = pkt; 
    729         frames[count].size = frame_size; 
     823    struct spx_private *spx = (struct spx_private*) codec->codec_data; 
     824    unsigned samples_per_frame; 
     825    unsigned count = 0; 
     826    int char_ptr = 0; 
     827    int bit_ptr = 0; 
     828 
     829    samples_per_frame=spx_factory.speex_param[spx->param_id].samples_per_frame; 
     830 
     831    /* Copy the data into the speex bit-stream */ 
     832    speex_bits_read_from(&spx->dec_bits, (char*)pkt, pkt_size); 
     833 
     834    while (speex_get_next_frame(&spx->dec_bits) == 0 &&  
     835           spx->dec_bits.charPtr != char_ptr) 
     836    { 
     837        frames[count].buf = (char*)pkt + char_ptr; 
     838        /* Bit info contains start bit offset of the frame */ 
     839        frames[count].bit_info = bit_ptr; 
    730840        frames[count].type = PJMEDIA_FRAME_TYPE_AUDIO; 
    731841        frames[count].timestamp.u64 = ts->u64 + count * samples_per_frame; 
    732  
    733         pkt_size -= frame_size; 
     842        frames[count].size = spx->dec_bits.charPtr - char_ptr; 
     843        if (spx->dec_bits.bitPtr) 
     844            ++frames[count].size; 
     845 
     846        bit_ptr = spx->dec_bits.bitPtr; 
     847        char_ptr = spx->dec_bits.charPtr; 
     848 
    734849        ++count; 
    735         pkt = ((char*)pkt) + frame_size; 
    736     } 
    737  
    738     /* Just in case speex has silence frame which size is less than normal 
    739      * frame size... 
    740      */ 
    741     if (pkt_size && count < *frame_cnt) { 
    742         frames[count].buf = pkt; 
    743         frames[count].size = pkt_size; 
    744         frames[count].type = PJMEDIA_FRAME_TYPE_AUDIO; 
    745         frames[count].timestamp.u64 = ts->u64 + count * samples_per_frame; 
    746         ++count; 
    747850    } 
    748851 
    749852    *frame_cnt = count; 
    750     return PJ_SUCCESS; 
    751 } 
    752  
    753 /* 
    754  * Encode frame. 
     853 
     854    return PJ_SUCCESS; 
     855} 
     856 
     857/* 
     858 * Encode frames. 
    755859 */ 
    756860static pj_status_t spx_codec_encode( pjmedia_codec *codec,  
     
    760864{ 
    761865    struct spx_private *spx; 
    762     unsigned sz; 
    763     int tx; 
     866    unsigned samples_per_frame; 
     867    int tx = 0; 
     868    spx_int16_t *pcm_in = (spx_int16_t*)input->buf; 
     869    unsigned nsamples; 
    764870 
    765871    spx = (struct spx_private*) codec->codec_data; 
     
    773879    } 
    774880 
     881    nsamples = input->size >> 1; 
     882    samples_per_frame=spx_factory.speex_param[spx->param_id].samples_per_frame; 
     883 
     884    PJ_ASSERT_RETURN(nsamples % samples_per_frame == 0,  
     885                     PJMEDIA_CODEC_EPCMFRMINLEN); 
     886 
    775887    /* Flush all the bits in the struct so we can encode a new frame */ 
    776888    speex_bits_reset(&spx->enc_bits); 
    777889 
    778     /* Encode the frame */ 
    779     tx = speex_encode_int(spx->enc, (spx_int16_t*)input->buf,  
    780                           &spx->enc_bits); 
     890    /* Encode the frames */ 
     891    while (nsamples >= samples_per_frame) { 
     892        tx += speex_encode_int(spx->enc, pcm_in, &spx->enc_bits); 
     893        pcm_in += samples_per_frame; 
     894        nsamples -= samples_per_frame; 
     895    } 
    781896 
    782897    /* Check if we need not to transmit the frame (DTX) */ 
     
    790905 
    791906    /* Check size. */ 
    792     sz = speex_bits_nbytes(&spx->enc_bits); 
    793     pj_assert(sz <= output_buf_len); 
     907    pj_assert(speex_bits_nbytes(&spx->enc_bits) <= (int)output_buf_len); 
    794908 
    795909    /* Copy the bits to an array of char that can be written */ 
     
    811925{ 
    812926    struct spx_private *spx; 
     927    unsigned samples_per_frame; 
    813928 
    814929    spx = (struct spx_private*) codec->codec_data; 
    815  
    816     PJ_ASSERT_RETURN(output_buf_len >= 320, PJMEDIA_CODEC_EPCMTOOSHORT); 
     930    samples_per_frame=spx_factory.speex_param[spx->param_id].samples_per_frame; 
     931 
     932    PJ_ASSERT_RETURN(output_buf_len >= samples_per_frame << 1, 
     933                     PJMEDIA_CODEC_EPCMTOOSHORT); 
    817934 
    818935    if (input->type != PJMEDIA_FRAME_TYPE_AUDIO) { 
    819         pjmedia_zero_samples((pj_int16_t*)output->buf, 160); 
    820         output->size = 320; 
     936        pjmedia_zero_samples((pj_int16_t*)output->buf, samples_per_frame); 
     937        output->size = samples_per_frame << 1; 
    821938        output->timestamp.u64 = input->timestamp.u64; 
    822939        output->type = PJMEDIA_FRAME_TYPE_AUDIO; 
     
    826943    /* Copy the data into the bit-stream struct */ 
    827944    speex_bits_read_from(&spx->dec_bits, (char*)input->buf, input->size); 
     945     
     946    /* Set Speex dec_bits pointer to the start bit of the frame */ 
     947    speex_bits_advance(&spx->dec_bits, input->bit_info); 
    828948 
    829949    /* Decode the data */ 
     
    831951 
    832952    output->type = PJMEDIA_FRAME_TYPE_AUDIO; 
    833     output->size = 320; 
     953    output->size = samples_per_frame << 1; 
    834954    output->timestamp.u64 = input->timestamp.u64; 
    835  
    836955 
    837956    return PJ_SUCCESS; 
Note: See TracChangeset for help on using the changeset viewer.