FFmpeg programming (III)

Source: Internet
Author: User

This article focuses on playing the video sound.

  audioStream = -1;    for (i = 0; i < pFormatCtx->nb_streams; i++) {        if (pFormatCtx->streams[i]->codec->codec_type == CODEC_TYPE_AUDIO                && audioStream < 0) {            audioStream = i;        }    }    if (audioStream == -1)        return -1;

The above code mainly finds the first audio stream.

aCodecCtx=pFormatCtx->streams[audioStream]->codec;

Record the context information of an audio decoder.

wanted_spec.freq = aCodecCtx->sample_rate;wanted_spec.format = AUDIO_S16SYS;wanted_spec.channels = aCodecCtx->channels;wanted_spec.silence = 0;wanted_spec.samples = SDL_AUDIO_BUFFER_SIZE;wanted_spec.callback = audio_callback;wanted_spec.userdata = aCodecCtx;

Wanted_spec is an sdl_audiospec struct.

Sdl_audiospec is a struct that contains the audio output format. It also contains the callback function called when the audio device requires more data.

Int

Freq

Sampling Rate

Sdl_audioformat

Format

Audio Data Format. Format indicates the format that SDL will give. In "s16sys", s indicates signed, 16 indicates that each sample is 16-bit long, and SYS indicates that the sequence of large and small headers is the same as that of the system used. These formats are the input audio formats provided by avcodec_decode_audio2.

Uint8

Channels

Sound channels: 1 single channel, 2 stereo;

Uint8

Silence

Indicates the mute value. Because sound sampling is signed, 0 is of course the value.

Uint16

Samples

Audio buffer size in samples (power of 2); For details, refer to "discussion"

Uint32

Size

The size of the audio cache (number of bytes). When we want more sound, we want the size of the sound buffer provided by SDL. A suitable value is between 512 and 8192; ffplay uses 1024.

Sdl_audiocallback

Callback

The callback function called when the audio device needs more data;

Void *

Userdata

This is the parameter that SDL provides for callback function operation. Let the callback function obtain the context information of the entire codec;

 

 

    if (SDL_OpenAudio(&wanted_spec, &spec) < 0) {        fprintf(stderr, "SDL_OpenAudio: %s/n", SDL_GetError());        return -1;    }

If your program can process different audio formats, use an sdl_audiospec pointer as the second parameter of sdl_openaudio () to obtain the real hardware audio format. If the second parameter is null, the audio data is converted to the hardware format at runtime.

aCodec = avcodec_find_decoder(aCodecCtx->codec_id);    if (!aCodec) {        fprintf(stderr, "Unsupported codec!/n");        return -1;    }

Avcodec_find_decoder (acodecctx-> codec_id); the function is responsible for finding the decoder.

avcodec_open(aCodecCtx, aCodec);

Enable the audio decoder.

Next we will read the audio from the file cyclically.

typedef struct PacketQueue {    AVPacketList *first_pkt, *last_pkt;    int nb_packets;    int size;    SDL_mutex *mutex;    SDL_cond *cond;} PacketQueue;

Then wanted_spec.callback = audio_callback; I have already explained that this is a callback function. This callback function is responsible for continuously playing the sound. What about this function? At this time, I need to apply for a piece of memory to store the sound. The callback function constantly reads data from the memory I applied for. This memory is the queue packetqueue.

Packetqueue uses the small linked list avpacketlist to form an ordered queue of audio frames avpacket.

Nb_packets: avpacket quantity

Size is the total size of avpacket. Size.

void packet_queue_init(PacketQueue *q) {    memset(q, 0, sizeof(PacketQueue));    q->mutex = SDL_CreateMutex();    q->cond = SDL_CreateCond();}

Initialize the queue.

The memset (Q, 0, sizeof (packetqueue) function is used to replace the first sizeof (packetqueue) bytes in Q with 0 and return Q;

The sdl_createmutex function is used to create a mutex. The return type is sdl_mutex.

Sdl_createcond creates a condition variable.

int packet_queue_put(PacketQueue *q, AVPacket *pkt) {    AVPacketList *pkt1;    if (av_dup_packet(pkt) < 0) {        return -1;    }    pkt1 = av_malloc(sizeof(AVPacketList));    if (!pkt1)        return -1;    pkt1->pkt = *pkt;    pkt1->next = NULL;    SDL_LockMutex(q->mutex);    if (!q->last_pkt)        q->first_pkt = pkt1;    else        q->last_pkt->next = pkt1;    q->last_pkt = pkt1;    q->nb_packets++;    q->size += pkt1->pkt.size;    SDL_CondSignal(q->cond);    SDL_UnlockMutex(q->mutex);    return 0;}

The function sdl_lockmutex () locks the mutex of the queue so that we can add data to the queue. Then the function sdl_condsignal () restarts the thread and waits for a condition variable (if it is waiting) send a signal to tell it that there is already data, and then unlock the mutex and allow free access to the queue.

int decode_interrupt_cb(void) {  return quit;}...main() {...  url_set_interrupt_cb(decode_interrupt_cb); ...     SDL_PollEvent(&event);  switch(event.type) {  case SDL_QUIT:    quit = 1;...

The url_set_interrupt_cb function performs callback and checks whether we need to exit some blocked functions.

In SDL, you must also set the quit flag to 1.

PacketQueue audioq;main() {...  avcodec_open(aCodecCtx, aCodec);   packet_queue_init(&audioq);  SDL_PauseAudio(0);

Initialize the packetqueue queue.

The function sdl_pauseaudio () enables the audio device to eventually start working. If you do not supply enough data immediately, it will play mute.

while(av_read_frame(pFormatCtx, &packet)>=0) {  // Is this a packet from the video stream?  if(packet.stream_index==videoStream) {    // Decode video frame    ....    }  } else if(packet.stream_index==audioStream) {    packet_queue_put(&audioq, &packet);  } else {    av_free_packet(&packet);  }

Read audio package information cyclically.

Void audio_callback (void * userdata, uint8 * stream, int Len ){
// Obtain the decoder context information avcodeccontext * acodecctx = (avcodeccontext *) userdata; int len1, audio_size; static uint8_t audio_buf [(avcodec_max_audio_frame_size * 3)/2]; static unsigned int audio_buf_size = 0; static unsigned int audio_buf_index = 0; while (LEN> 0) {If (audio_buf_index> = audio_buf_size ){
// Custom audio decoder method audio_size = audio (acodecctx, audio_buf, sizeof (audio_buf); If (audio_size <0) {audio_buf_size = 1024; memset (audio_buf, 0, bytes);} else {audio_buf_size = audio_size;} audio_buf_index = 0;} len1 = bytes-audio_buf_index; If (len1> Len) len1 = Len; memcpy (stream, (uint8_t *) audio_buf + audio_buf_index, len1); Len-= len1; stream + = len1; audio_buf_index + = len1 ;}}
int audio_decode_frame(AVCodecContext *aCodecCtx, uint8_t *audio_buf,int buf_size) {    static AVPacket pkt;    static uint8_t *audio_pkt_data = NULL;    static int audio_pkt_size = 0;    int len1, data_size;    for (;;) {        while (audio_pkt_size > 0) {            data_size = buf_size;            len1 = avcodec_decode_audio2(aCodecCtx, (int16_t *) audio_buf,                    &data_size,                    audio_pkt_data, audio_pkt_size);            if (len1 < 0) {                audio_pkt_size = 0;                break;            }            audio_pkt_data += len1;            audio_pkt_size -= len1;            if (data_size <= 0) {                continue;            }            return data_size;        }        if (pkt.data)            av_free_packet(&pkt);        if (quit) {            return -1;        }        if (packet_queue_get(&audioq, &pkt, 1) < 0) {            return -1;        }        audio_pkt_data = pkt.data;        audio_pkt_size = pkt.size;    }}

 

 

int quit = 0;static int packet_queue_get(PacketQueue *q, AVPacket *pkt, int block) {  AVPacketList *pkt1;  int ret;  SDL_LockMutex(q->mutex);  for(;;) {    if(quit) {      ret = -1;      break;    }    pkt1 = q->first_pkt;    if (pkt1) {      q->first_pkt = pkt1->next;      if (!q->first_pkt)     q->last_pkt = NULL;      q->nb_packets--;      q->size -= pkt1->pkt.size;      *pkt = pkt1->pkt;      av_free(pkt1);      ret = 1;      break;    } else if (!block) {      ret = 0;      break;    } else {      SDL_CondWait(q->cond, q->mutex);    }  }  SDL_UnlockMutex(q->mutex);  return ret;}

This code is probably to execute the main function first, enable the sub-thread audio_callback () to constantly read the audio stream, and then use audio_decode_frame () to decode the decoded data from packet_queue_get,

The main function packet_queue_put () is used to put audio frames in the queue so that packet_queue_get () can be obtained from the queue.

C File Download

Http://download.csdn.net/detail/wenwei19861106/4221053

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.