Ignore:
Timestamp:
Sep 10, 2008 7:48:45 PM (16 years ago)
Author:
nanang
Message:

Ticket #614: Added support for writing and reading WAV files encoded as 8 bit A-law/U-law.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • pjproject/trunk/pjmedia/src/pjmedia/wav_writer.c

    r2039 r2270  
    1818 */ 
    1919#include <pjmedia/wav_port.h> 
     20#include <pjmedia/alaw_ulaw.h> 
    2021#include <pjmedia/errno.h> 
    2122#include <pjmedia/wave.h> 
     
    3031#define THIS_FILE           "wav_writer.c" 
    3132#define SIGNATURE           PJMEDIA_PORT_SIGNATURE('F', 'W', 'R', 'T') 
    32 #define BYTES_PER_SAMPLE    2 
    3333 
    3434 
     
    3636{ 
    3737    pjmedia_port     base; 
     38    pjmedia_wave_fmt_tag fmt_tag; 
     39    pj_uint16_t      bytes_per_sample; 
     40 
    3841    pj_size_t        bufsize; 
    3942    char            *buf; 
     
    7376    pj_status_t status; 
    7477 
    75     PJ_UNUSED_ARG(flags); 
    76  
    7778    /* Check arguments. */ 
    7879    PJ_ASSERT_RETURN(pool && filename && p_port, PJ_EINVAL); 
     
    9798    fport->base.on_destroy = &file_on_destroy; 
    9899 
     100    if (flags == PJMEDIA_FILE_WRITE_ALAW) { 
     101        fport->fmt_tag = PJMEDIA_WAVE_FMT_TAG_ALAW; 
     102        fport->bytes_per_sample = 1; 
     103    } else if (flags == PJMEDIA_FILE_WRITE_ULAW) { 
     104        fport->fmt_tag = PJMEDIA_WAVE_FMT_TAG_ULAW; 
     105        fport->bytes_per_sample = 1; 
     106    } else { 
     107        fport->fmt_tag = PJMEDIA_WAVE_FMT_TAG_PCM; 
     108        fport->bytes_per_sample = 2; 
     109    } 
    99110 
    100111    /* Open file in write and read mode. 
     
    114125    wave_hdr.fmt_hdr.fmt = PJMEDIA_FMT_TAG; 
    115126    wave_hdr.fmt_hdr.len = 16; 
    116     wave_hdr.fmt_hdr.fmt_tag = 1; 
     127    wave_hdr.fmt_hdr.fmt_tag = fport->fmt_tag; 
    117128    wave_hdr.fmt_hdr.nchan = (pj_int16_t)channel_count; 
    118129    wave_hdr.fmt_hdr.sample_rate = sampling_rate; 
    119130    wave_hdr.fmt_hdr.bytes_per_sec = sampling_rate * channel_count *  
    120                                      bits_per_sample / 8; 
    121     wave_hdr.fmt_hdr.block_align = (pj_int16_t) (channel_count *  
    122                                                  bits_per_sample / 8); 
    123     wave_hdr.fmt_hdr.bits_per_sample = (pj_int16_t)bits_per_sample; 
     131                                     fport->bytes_per_sample; 
     132    wave_hdr.fmt_hdr.block_align = fport->bytes_per_sample * channel_count; 
     133    wave_hdr.fmt_hdr.bits_per_sample = fport->bytes_per_sample * 8; 
    124134 
    125135    wave_hdr.data_hdr.data = PJMEDIA_DATA_TAG; 
     
    134144 
    135145    /* Write WAVE header */ 
    136     size = sizeof(pjmedia_wave_hdr); 
    137     status = pj_file_write(fport->fd, &wave_hdr, &size); 
    138     if (status != PJ_SUCCESS) { 
    139         pj_file_close(fport->fd); 
    140         return status; 
     146    if (fport->fmt_tag != PJMEDIA_WAVE_FMT_TAG_PCM) { 
     147        pjmedia_wave_subchunk fact_chunk; 
     148        pj_uint32_t tmp = 0; 
     149 
     150        fact_chunk.id = PJMEDIA_FACT_TAG; 
     151        fact_chunk.len = 4; 
     152 
     153        PJMEDIA_WAVE_NORMALIZE_SUBCHUNK(&fact_chunk); 
     154 
     155        /* Write WAVE header without DATA chunk header */ 
     156        size = sizeof(pjmedia_wave_hdr) - sizeof(wave_hdr.data_hdr); 
     157        status = pj_file_write(fport->fd, &wave_hdr, &size); 
     158        if (status != PJ_SUCCESS) { 
     159            pj_file_close(fport->fd); 
     160            return status; 
     161        } 
     162 
     163        /* Write FACT chunk if it stores compressed data */ 
     164        size = sizeof(fact_chunk); 
     165        status = pj_file_write(fport->fd, &fact_chunk, &size); 
     166        if (status != PJ_SUCCESS) { 
     167            pj_file_close(fport->fd); 
     168            return status; 
     169        } 
     170        size = 4; 
     171        status = pj_file_write(fport->fd, &tmp, &size); 
     172        if (status != PJ_SUCCESS) { 
     173            pj_file_close(fport->fd); 
     174            return status; 
     175        } 
     176 
     177        /* Write DATA chunk header */ 
     178        size = sizeof(wave_hdr.data_hdr); 
     179        status = pj_file_write(fport->fd, &wave_hdr.data_hdr, &size); 
     180        if (status != PJ_SUCCESS) { 
     181            pj_file_close(fport->fd); 
     182            return status; 
     183        } 
     184    } else { 
     185        size = sizeof(pjmedia_wave_hdr); 
     186        status = pj_file_write(fport->fd, &wave_hdr, &size); 
     187        if (status != PJ_SUCCESS) { 
     188            pj_file_close(fport->fd); 
     189            return status; 
     190        } 
    141191    } 
    142192 
     
    259309{ 
    260310    struct file_port *fport = (struct file_port *)this_port; 
     311    unsigned frame_size; 
     312 
     313    if (fport->fmt_tag == PJMEDIA_WAVE_FMT_TAG_PCM) 
     314        frame_size = frame->size; 
     315    else 
     316        frame_size = frame->size >> 1; 
    261317 
    262318    /* Flush buffer if we don't have enough room for the frame. */ 
    263     if (fport->writepos + frame->size > fport->buf + fport->bufsize) { 
     319    if (fport->writepos + frame_size > fport->buf + fport->bufsize) { 
    264320        pj_status_t status; 
    265321        status = flush_buffer(fport); 
     
    269325 
    270326    /* Check if frame is not too large. */ 
    271     PJ_ASSERT_RETURN(fport->writepos+frame->size <= fport->buf+fport->bufsize, 
     327    PJ_ASSERT_RETURN(fport->writepos+frame_size <= fport->buf+fport->bufsize, 
    272328                     PJMEDIA_EFRMFILETOOBIG); 
    273329 
    274330    /* Copy frame to buffer. */ 
    275     pj_memcpy(fport->writepos, frame->buf, frame->size); 
    276     fport->writepos += frame->size; 
     331    if (fport->fmt_tag == PJMEDIA_WAVE_FMT_TAG_PCM) { 
     332        pj_memcpy(fport->writepos, frame->buf, frame->size); 
     333    } else { 
     334        unsigned i; 
     335        pj_int16_t *src = (pj_int16_t*)frame->buf; 
     336        pj_uint8_t *dst = (pj_uint8_t*)fport->writepos; 
     337 
     338        if (fport->fmt_tag == PJMEDIA_WAVE_FMT_TAG_ULAW) { 
     339            for (i = 0; i < frame_size; ++i) { 
     340                *dst++ = pjmedia_linear2ulaw(*src++); 
     341            } 
     342        } else { 
     343            for (i = 0; i < frame_size; ++i) { 
     344                *dst++ = pjmedia_linear2alaw(*src++); 
     345            } 
     346        } 
     347 
     348    } 
     349    fport->writepos += frame_size; 
    277350 
    278351    /* Increment total written, and check if we need to call callback */ 
    279     fport->total += frame->size; 
     352    fport->total += frame_size; 
    280353    if (fport->cb && fport->total >= fport->cb_size) { 
    281354        pj_status_t (*cb)(pjmedia_port*, void*); 
     
    315388    pj_uint32_t wave_data_len; 
    316389    pj_status_t status; 
     390    pj_uint32_t data_len_pos = DATA_LEN_POS; 
    317391 
    318392    /* Flush remaining buffers. */ 
     
    342416    PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); 
    343417 
     418    /* Write samples_len in FACT chunk */ 
     419    if (fport->fmt_tag != PJMEDIA_WAVE_FMT_TAG_PCM) { 
     420        enum { SAMPLES_LEN_POS = 44}; 
     421        pj_uint32_t wav_samples_len; 
     422 
     423        /* Adjust wave_data_len & data_len_pos since there is FACT chunk */ 
     424        wave_data_len -= 12; 
     425        data_len_pos += 12; 
     426        wav_samples_len = wave_data_len; 
     427 
     428        /* Seek to samples_len field. */ 
     429        status = pj_file_setpos(fport->fd, SAMPLES_LEN_POS, PJ_SEEK_SET); 
     430        PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); 
     431 
     432        /* Write samples_len */ 
     433        bytes = sizeof(wav_samples_len); 
     434        status = pj_file_write(fport->fd, &wav_samples_len, &bytes); 
     435        PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); 
     436    } 
     437 
    344438    /* Seek to data_len field. */ 
    345     status = pj_file_setpos(fport->fd, DATA_LEN_POS, PJ_SEEK_SET); 
     439    status = pj_file_setpos(fport->fd, data_len_pos, PJ_SEEK_SET); 
    346440    PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); 
    347441 
Note: See TracChangeset for help on using the changeset viewer.