Added libav audio encoding logic.

This commit is contained in:
mjbudd77 2021-09-07 20:59:59 -04:00
parent f3ce245746
commit e4cd3b0d1a
1 changed files with 123 additions and 4 deletions

View File

@ -714,6 +714,7 @@ struct OutputStream
AVFrame *tmp_frame;
struct SwsContext *sws_ctx;
AVAudioResampleContext *avr;
int64_t next_pts;
OutputStream(void)
{
@ -722,6 +723,7 @@ struct OutputStream
frame = tmp_frame = NULL;
sws_ctx = NULL;
avr = NULL;
next_pts = 0;
}
void close(void)
@ -742,6 +744,7 @@ struct OutputStream
{
avresample_free(&avr); avr = NULL;
}
next_pts = 0;
}
};
static OutputStream video_st;
@ -776,6 +779,9 @@ static int initVideoStream( enum AVCodecID codec_id, OutputStream *ost )
int ret;
AVCodec *codec;
AVCodecContext *c;
double fps;
fps = getBaseFrameRate();
/* find the video encoder */
codec = avcodec_find_encoder(codec_id);
@ -814,12 +820,12 @@ static int initVideoStream( enum AVCodecID codec_id, OutputStream *ost )
* of which frame timestamps are represented. For fixed-fps content,
* timebase should be 1/framerate and timestamp increments should be
* identical to 1. */
ost->st->time_base = (AVRational){ 1, 60 };
ost->st->time_base = (AVRational){ 1000, fps * 1000 };
c->time_base = ost->st->time_base;
c->gop_size = 12; /* emit one intra frame every twelve frames at most */
c->pix_fmt = AV_PIX_FMT_YUV420P;
printf("PIX_FMT:%i\n", c->pix_fmt );
//printf("PIX_FMT:%i\n", c->pix_fmt );
if (c->codec_id == AV_CODEC_ID_MPEG2VIDEO)
{
@ -1086,6 +1092,117 @@ static int init( int width, int height )
return 0;
}
static int encode_audio_frame( int16_t *audioOut, int numSamples)
{
int i,j, ret;
OutputStream *ost = &audio_st;
AVFrame *frame = NULL;
if ( audioOut )
{
frame = ost->tmp_frame;
int16_t *q = (int16_t*)frame->data[0];
for (j = 0; j < numSamples; j++)
{
for (i = 0; i < ost->enc->channels; i++)
{
*q++ = audioOut[j];
}
}
frame->nb_samples = numSamples;
ret = avresample_convert(ost->avr, NULL, 0, 0,
frame->extended_data, frame->linesize[0],
frame->nb_samples);
if (ret < 0)
{
fprintf(stderr, "Error feeding audio data to the resampler\n");
return -1;
}
}
while ( ( frame && (avresample_available(ost->avr) >= ost->frame->nb_samples)) ||
(!frame && (avresample_get_out_samples(ost->avr, 0) > 0) ) )
{
/* when we pass a frame to the encoder, it may keep a reference to it
* internally;
* make sure we do not overwrite it here
*/
ret = av_frame_make_writable(ost->frame);
if (ret < 0)
{
return -1;
}
/* the difference between the two avresample calls here is that the
* first one just reads the already converted data that is buffered in
* the lavr output buffer, while the second one also flushes the
* resampler */
if ( frame )
{
ret = avresample_read(ost->avr, ost->frame->extended_data,
ost->frame->nb_samples);
}
else
{
ret = avresample_convert(ost->avr, ost->frame->extended_data,
ost->frame->linesize[0], ost->frame->nb_samples,
NULL, 0, 0);
}
if (ret < 0)
{
fprintf(stderr, "Error while resampling\n");
return -1;
}
else if ( frame && (ret != ost->frame->nb_samples) )
{
fprintf(stderr, "Too few samples returned from lavr\n");
return -1;
}
ost->frame->nb_samples = ret;
ost->frame->pts = ost->next_pts;
ost->next_pts += ost->frame->nb_samples;
//got_output |= encode_audio_frame(oc, ost, ret ? ost->frame : NULL);
if ( ret == 0 )
{
fprintf(stderr, "Last Audio Frame\n");
}
ret = avcodec_send_frame(ost->enc, (ret > 0) ? ost->frame : NULL);
if (ret < 0)
{
fprintf(stderr, "Error submitting a frame for encoding\n");
return -1;
}
while (ret >= 0)
{
AVPacket pkt = { 0 }; // data and size must be 0;
av_init_packet(&pkt);
ret = avcodec_receive_packet(ost->enc, &pkt);
if (ret < 0 && ret != AVERROR(EAGAIN) && ret != AVERROR_EOF)
{
fprintf(stderr, "Error encoding a video frame\n");
return -1;
}
else if (ret >= 0)
{
av_packet_rescale_ts(&pkt, ost->enc->time_base, ost->st->time_base);
pkt.stream_index = ost->st->index;
/* Write the compressed frame to the media file. */
ret = av_interleaved_write_frame(oc, &pkt);
if (ret < 0)
{
fprintf(stderr, "Error while writing video frame\n");
return -1;
}
}
}
}
return 0;
}
static int encode_video_frame( unsigned char *inBuf )
{
int ret, y, ofs, inLineSize;
@ -1117,7 +1234,7 @@ static int encode_video_frame( unsigned char *inBuf )
ost->tmp_frame->linesize, 0, c->height, ost->frame->data,
ost->frame->linesize);
video_st.frame->pts++;
video_st.frame->pts = video_st.next_pts++;
/* encode the image */
ret = avcodec_send_frame(c, video_st.frame);
@ -1159,6 +1276,8 @@ static int encode_video_frame( unsigned char *inBuf )
static int close(void)
{
encode_audio_frame( NULL, 0 );
/* Write the trailer, if any. The trailer must be written before you
* close the CodecContexts open when you wrote the header; otherwise
* av_write_trailer() may try to use memory that was freed on
@ -1708,7 +1827,7 @@ void AviRecordDiskThread_t::run(void)
#ifdef _USE_LIBAV
if ( localVideoFormat == AVI_LIBAV)
{
LIBAV::encode_audio_frame( audioOut, numSamples );
}
else
#endif