/** * libao + ffmpeg test * compile with: gcc -lavformat -lavcodec -lao -ldl -lm -lz -o libao+ffmpeg libao+ffmpeg.c */ #include #include #include #include #include #include #include #define BUF_SIZE 4096 AVCodecContext *aCodecCtx; ao_device *device; typedef struct PacketQueue { AVPacketList *first_pkt, *last_pkt; int nb_packets; int size; pthread_mutex_t mutex; pthread_cond_t cond; } PacketQueue; PacketQueue audioq; int done = 0; void packet_queue_init(PacketQueue *q) { memset(q, 0, sizeof(PacketQueue)); pthread_mutex_init(&q->mutex, NULL); pthread_cond_init(&q->cond, NULL); } 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; pthread_mutex_lock (&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; pthread_cond_signal(&q->cond); pthread_mutex_unlock (&q->mutex); return 0; } int packet_queue_get(PacketQueue *q, AVPacket *pkt, int block) { AVPacketList *pkt1; int ret; pthread_mutex_lock (&q->mutex); for(;;) { if(done && !q->nb_packets) { 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 { pthread_cond_wait(&q->cond, &q->mutex); } } pthread_mutex_unlock (&q->mutex); return ret; } void *play(void *t) { AVPacket pkt; int data_size = (AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 2; static uint8_t audio_buf[(AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 2]; for (;;) { if(packet_queue_get(&audioq, &pkt, 1) < 0) break; int temp = data_size; avcodec_decode_audio2(aCodecCtx, (int16_t *)audio_buf, &temp, pkt.data, pkt.size); ao_play(device, audio_buf, temp); av_free_packet(&pkt); } pthread_exit(NULL); } int main(int argc, char *argv[]) { AVCodec *aCodec; AVFormatContext *pFormatCtx; AVPacket packet; ao_sample_format format; int default_driver; int audioStream; int i; pthread_t thread; if(argc < 2) { fprintf(stderr, "Usage: test \n"); exit(1); } /* -- Initialize -- */ av_register_all(); ao_initialize(); default_driver = ao_default_driver_id(); /* -- Open file -- */ if(av_open_input_file(&pFormatCtx, argv[1], NULL, 0, NULL)!=0) return -1; if(av_find_stream_info(pFormatCtx)<0) return -1; /* -- Find audio stream */ audioStream=-1; for(i=0; inb_streams; i++) { if(pFormatCtx->streams[i]->codec->codec_type==CODEC_TYPE_AUDIO && audioStream < 0) { audioStream=i; } } if(audioStream==-1) return -1; aCodecCtx=pFormatCtx->streams[audioStream]->codec; /* -- Set format -- */ format.bits = 16; format.channels = aCodecCtx->channels; format.rate = aCodecCtx->sample_rate; format.byte_format = AO_FMT_LITTLE; /* -- Open driver -- */ device = ao_open_live(default_driver, &format, NULL); if (device == NULL) { fprintf(stderr, "Error opening device.\n"); return 1; } /* -- Open codec -- */ aCodec = avcodec_find_decoder(aCodecCtx->codec_id); if(!aCodec) { fprintf(stderr, "Unsupported codec!\n"); return -1; } avcodec_open(aCodecCtx, aCodec); /* -- Read packets & play them -- */ packet_queue_init(&audioq); pthread_create(&thread, NULL, play, NULL); while(av_read_frame(pFormatCtx, &packet)>=0) { if(packet.stream_index==audioStream) { packet_queue_put(&audioq, &packet); } else { av_free_packet(&packet); } } done=1; /* -- Close -- */ pthread_cond_destroy(&audioq.cond); pthread_mutex_destroy(&audioq.mutex); pthread_exit(NULL); avcodec_close(aCodecCtx); av_close_input_file(pFormatCtx); ao_close(device); ao_shutdown(); return 0; }