static void encode_audio_and_write(struct ao *ao, AVFrame *frame) { // TODO: Can we unify this with the equivalent video code path? struct priv *ac = ao->priv; AVPacket packet = {0}; #if HAVE_AVCODEC_NEW_CODEC_API int status = avcodec_send_frame(ac->codec, frame); if (status < 0) { MP_ERR(ao, "error encoding at %d %d/%d\n", frame ? (int) frame->pts : -1, ac->codec->time_base.num, ac->codec->time_base.den); return; } for (;;) { av_init_packet(&packet); status = avcodec_receive_packet(ac->codec, &packet); if (status == AVERROR(EAGAIN)) { // No more packets for now. if (frame == NULL) { MP_ERR(ao, "sent flush frame, got EAGAIN"); } break; } if (status == AVERROR_EOF) { // No more packets, ever. if (frame != NULL) { MP_ERR(ao, "sent audio frame, got EOF"); } break; } if (status < 0) { MP_ERR(ao, "error encoding at %d %d/%d\n", frame ? (int) frame->pts : -1, ac->codec->time_base.num, ac->codec->time_base.den); break; } if (frame) { if (ac->savepts == AV_NOPTS_VALUE) ac->savepts = frame->pts; } encode_lavc_write_stats(ao->encode_lavc_ctx, ac->codec); write_packet(ao, &packet); av_packet_unref(&packet); } #else av_init_packet(&packet); int got_packet = 0; int status = avcodec_encode_audio2(ac->codec, &packet, frame, &got_packet); if (status < 0) { MP_ERR(ao, "error encoding at %d %d/%d\n", frame ? (int) frame->pts : -1, ac->codec->time_base.num, ac->codec->time_base.den); return; } if (!got_packet) { return; } if (frame) { if (ac->savepts == AV_NOPTS_VALUE) ac->savepts = frame->pts; } encode_lavc_write_stats(ao->encode_lavc_ctx, ac->codec); write_packet(ao, &packet); av_packet_unref(&packet); #endif }
// must get exactly ac->aframesize amount of data static int encode(struct ao *ao, double apts, void **data) { AVPacket packet; struct priv *ac = ao->priv; struct encode_lavc_context *ectx = ao->encode_lavc_ctx; double realapts = ac->aframecount * (double) ac->aframesize / ao->samplerate; int status, gotpacket; ac->aframecount++; if (data) ectx->audio_pts_offset = realapts - apts; av_init_packet(&packet); packet.data = ac->buffer; packet.size = ac->buffer_size; if(data) { AVFrame *frame = av_frame_alloc(); frame->format = af_to_avformat(ao->format); frame->nb_samples = ac->aframesize; assert(ao->channels.num <= AV_NUM_DATA_POINTERS); for (int n = 0; n < ao->channels.num; n++) frame->extended_data[n] = data[n]; frame->linesize[0] = frame->nb_samples * ao->sstride; if (ectx->options->rawts || ectx->options->copyts) { // real audio pts frame->pts = floor(apts * ac->stream->codec->time_base.den / ac->stream->codec->time_base.num + 0.5); } else { // audio playback time frame->pts = floor(realapts * ac->stream->codec->time_base.den / ac->stream->codec->time_base.num + 0.5); } int64_t frame_pts = av_rescale_q(frame->pts, ac->stream->codec->time_base, ac->worst_time_base); if (ac->lastpts != MP_NOPTS_VALUE && frame_pts <= ac->lastpts) { // this indicates broken video // (video pts failing to increase fast enough to match audio) MP_WARN(ao, "audio frame pts went backwards (%d <- %d), autofixed\n", (int)frame->pts, (int)ac->lastpts); frame_pts = ac->lastpts + 1; frame->pts = av_rescale_q(frame_pts, ac->worst_time_base, ac->stream->codec->time_base); } ac->lastpts = frame_pts; frame->quality = ac->stream->codec->global_quality; status = avcodec_encode_audio2(ac->stream->codec, &packet, frame, &gotpacket); if (!status) { if (ac->savepts == MP_NOPTS_VALUE) ac->savepts = frame->pts; } av_frame_free(&frame); } else { status = avcodec_encode_audio2(ac->stream->codec, &packet, NULL, &gotpacket); } if(status) { MP_ERR(ao, "error encoding\n"); return -1; } if(!gotpacket) return 0; MP_DBG(ao, "got pts %f (playback time: %f); out size: %d\n", apts, realapts, packet.size); encode_lavc_write_stats(ao->encode_lavc_ctx, ac->stream); packet.stream_index = ac->stream->index; // Do we need this at all? Better be safe than sorry... if (packet.pts == AV_NOPTS_VALUE) { MP_WARN(ao, "encoder lost pts, why?\n"); if (ac->savepts != MP_NOPTS_VALUE) packet.pts = ac->savepts; } if (packet.pts != AV_NOPTS_VALUE) packet.pts = av_rescale_q(packet.pts, ac->stream->codec->time_base, ac->stream->time_base); if (packet.dts != AV_NOPTS_VALUE) packet.dts = av_rescale_q(packet.dts, ac->stream->codec->time_base, ac->stream->time_base); if(packet.duration > 0) packet.duration = av_rescale_q(packet.duration, ac->stream->codec->time_base, ac->stream->time_base); ac->savepts = MP_NOPTS_VALUE; if (encode_lavc_write_frame(ao->encode_lavc_ctx, &packet) < 0) { MP_ERR(ao, "error writing at %f %f/%f\n", realapts, (double) ac->stream->time_base.num, (double) ac->stream->time_base.den); return -1; } return packet.size; }