int ffaml_queue_packet(AVCodecContext *avctx, PacketQueue *queue, AVPacket *avpkt) { int ret = 0; // create our packet entry for the queue PacketEntry *packetentry = malloc(sizeof(*packetentry)); if (!packetentry) { ret = AVERROR(ENOMEM); goto done; } packetentry->pkt = av_packet_clone(avpkt); packetentry->next = NULL; packetentry->prev = NULL; if (!packetentry->pkt) av_log(avctx, AV_LOG_ERROR, "queuing null packet !!\n"); // add the packet to start of the queue if (queue->head) { packetentry->next = queue->head; queue->head->prev = packetentry; } if (!queue->tail) queue->tail = packetentry; queue->head = packetentry; queue->size++; #if DEBUG av_log(avctx, AV_LOG_DEBUG, "queued packet in %x, entry=%x, pkt=%x size= %d\n", queue, packetentry,packetentry->pkt, queue->size); #endif return 0; done: return ret; }
bool FFmpegAudioReader::readFrame(AVFrame* decode_frame) { // FFmpeg 3.1 and onwards has a new, better packet handling API but that version is relatively new so we still need // to support the earlier API. The compatibility code can be removed once the new version is supported by most platforms #if LIBAVCODEC_VERSION_INT > AV_VERSION_INT(57, 24, 255) // Process pending frames auto pending_res = avcodec_receive_frame(_codec_ctx, decode_frame); if (pending_res == 0) { // Got a frame return true; } if (pending_res == AVERROR_EOF) { // No more frames available return false; } if (pending_res != AVERROR(EAGAIN)) { // Unknown error. return false; } #else if (_currentPacket != nullptr) { // Got some data left int finishedFrame = 0; auto bytes_read = avcodec_decode_audio4(_codec_ctx, decode_frame, &finishedFrame, _currentPacket); if (bytes_read < 0) { // Error! return false; } _currentPacket->data += bytes_read; _currentPacket->size -= bytes_read; if (_currentPacket->size <= 0) { // Done with this packet av_packet_free(&_currentPacket); } if (finishedFrame) { return true; } } #endif AVPacket packet; while (av_read_frame(_format_ctx, &packet) >= 0) { AVPacketScope packet_scope(&packet); if (packet.stream_index == _stream_idx) { #if LIBAVCODEC_VERSION_INT > AV_VERSION_INT(57, 24, 255) auto res = avcodec_send_packet(_codec_ctx, &packet); if (res != 0) { // Error or EOF return false; } res = avcodec_receive_frame(_codec_ctx, decode_frame); if (res == 0) { // Got a frame return true; } if (res == AVERROR_EOF) { // No more frames available return false; } if (res != AVERROR(EAGAIN)) { // Unknown error. return false; } // EGAIN was returned, send new input #else int finishedFrame = 0; auto bytes_read = avcodec_decode_audio4(_codec_ctx, decode_frame, &finishedFrame, &packet); if (bytes_read < packet.size) { // Not all data was read packet.data += bytes_read; packet.size -= bytes_read; _currentPacket = av_packet_clone(&packet); } if (finishedFrame) { return true; } if (bytes_read < 0) { // Error return false; } #endif } } #if LIBAVCODEC_VERSION_INT > AV_VERSION_INT(57, 24, 255) // Flush decoder if (avcodec_send_packet(_codec_ctx, nullptr) != 0) { return false; } auto flush_res = avcodec_receive_frame(_codec_ctx, decode_frame); if (flush_res == 0) { // Got a frame return true; } #else AVPacket nullPacket; memset(&nullPacket, 0, sizeof(nullPacket)); nullPacket.data = nullptr; nullPacket.size = 0; int finishedFrame = 1; auto err = avcodec_decode_audio4(_codec_ctx, decode_frame, &finishedFrame, &nullPacket); if (finishedFrame && err >= 0) { return true; } #endif // If we are here then read_frame reached the end or returned an error return false; }