int av_buffersink_read_samples(AVFilterContext *ctx, AVFilterBufferRef **pbuf, int nb_samples) { BufferSinkContext *s = ctx->priv; AVFilterLink *link = ctx->inputs[0]; int ret = 0; if (!s->audio_fifo) { int nb_channels = av_get_channel_layout_nb_channels(link->channel_layout); if (!(s->audio_fifo = av_audio_fifo_alloc(link->format, nb_channels, nb_samples))) return AVERROR(ENOMEM); } while (ret >= 0) { AVFilterBufferRef *buf; if (av_audio_fifo_size(s->audio_fifo) >= nb_samples) return read_from_fifo(ctx, pbuf, nb_samples); ret = av_buffersink_read(ctx, &buf); if (ret == AVERROR_EOF && av_audio_fifo_size(s->audio_fifo)) return read_from_fifo(ctx, pbuf, av_audio_fifo_size(s->audio_fifo)); else if (ret < 0) return ret; if (buf->pts != AV_NOPTS_VALUE) { s->next_pts = buf->pts - av_rescale_q(av_audio_fifo_size(s->audio_fifo), (AVRational){ 1, link->sample_rate }, link->time_base); } ret = av_audio_fifo_write(s->audio_fifo, (void**)buf->extended_data, buf->audio->nb_samples); avfilter_unref_buffer(buf); } return ret; }
/* decode and play stream. returns 0 or av error code. */ static int play (player_t * const player) { assert (player != NULL); AVPacket pkt; av_init_packet (&pkt); pkt.data = NULL; pkt.size = 0; AVFrame *frame = NULL, *filteredFrame = NULL; frame = avcodec_alloc_frame (); assert (frame != NULL); filteredFrame = avcodec_alloc_frame (); assert (filteredFrame != NULL); while (!player->doQuit) { ping (); int ret = av_read_frame (player->fctx, &pkt); if (ret < 0) { av_free_packet (&pkt); return ret; } else if (pkt.stream_index != player->streamIdx) { av_free_packet (&pkt); continue; } AVPacket pkt_orig = pkt; /* pausing */ pthread_mutex_lock (&player->pauseMutex); while (true) { if (!player->doPause) { av_read_play (player->fctx); break; } else { av_read_pause (player->fctx); } pthread_cond_wait (&player->pauseCond, &player->pauseMutex); } pthread_mutex_unlock (&player->pauseMutex); do { int got_frame = 0; const int decoded = avcodec_decode_audio4 (player->st->codec, frame, &got_frame, &pkt); if (decoded < 0) { /* skip this one */ break; } if (got_frame != 0) { /* XXX: suppresses warning from resample filter */ if (frame->pts == (int64_t) AV_NOPTS_VALUE) { frame->pts = 0; } ret = av_buffersrc_write_frame (player->fabuf, frame); assert (ret >= 0); while (true) { AVFilterBufferRef *audioref = NULL; #ifdef HAVE_AV_BUFFERSINK_GET_BUFFER_REF /* ffmpeg’s compatibility layer is broken in some releases */ if (av_buffersink_get_buffer_ref (player->fbufsink, &audioref, 0) < 0) { #else if (av_buffersink_read (player->fbufsink, &audioref) < 0) { #endif /* try again next frame */ break; } ret = avfilter_copy_buf_props (filteredFrame, audioref); assert (ret >= 0); const int numChannels = av_get_channel_layout_nb_channels ( filteredFrame->channel_layout); const int bps = av_get_bytes_per_sample(filteredFrame->format); ao_play (player->aoDev, (char *) filteredFrame->data[0], filteredFrame->nb_samples * numChannels * bps); avfilter_unref_bufferp (&audioref); } } pkt.data += decoded; pkt.size -= decoded; } while (pkt.size > 0); av_free_packet (&pkt_orig); player->songPlayed = av_q2d (player->st->time_base) * (double) pkt.pts; player->lastTimestamp = pkt.pts; } avcodec_free_frame (&filteredFrame); avcodec_free_frame (&frame); return 0; } static void finish (player_t * const player) { ao_close (player->aoDev); player->aoDev = NULL; if (player->fgraph != NULL) { avfilter_graph_free (&player->fgraph); player->fgraph = NULL; } if (player->st != NULL && player->st->codec != NULL) { avcodec_close (player->st->codec); player->st = NULL; } if (player->fctx != NULL) { avformat_close_input (&player->fctx); } }