obs-ffmpeg: Use av_packet_alloc instead of av_init_packet

sizeof(AVPacket) being a part of the public ABI is deprecated. once
av_init_packet() is removed, new packets will only be able to be
allocated with av_packet_alloc().
In ffmpeg-mux, ffmpeg-vaapi, and obs-ffmpeg-nvenc, AVPacket is allocated
at the initialization to avoid frequent allocation of AVPacket.

Includes changes to win-dshow.
master
Norihiro Kamae 2022-01-08 19:02:42 +09:00 committed by Jim
parent 85addc3dac
commit ba68eda590
5 changed files with 159 additions and 129 deletions

View File

@ -119,6 +119,7 @@ struct ffmpeg_mux {
AVFormatContext *output;
AVStream *video_stream;
AVCodecContext *video_ctx;
AVPacket *packet;
struct audio_info *audio_infos;
struct main_params params;
struct audio_params *audio;
@ -181,6 +182,8 @@ static void ffmpeg_mux_free(struct ffmpeg_mux *ffm)
dstr_free(&ffm->params.printable_file);
av_packet_free(&ffm->packet);
memset(ffm, 0, sizeof(*ffm));
}
@ -717,6 +720,8 @@ static int ffmpeg_mux_init_internal(struct ffmpeg_mux *ffm, int argc,
if (!ffmpeg_mux_get_extra_data(ffm))
return FFM_ERROR;
ffm->packet = av_packet_alloc();
/* ffmpeg does not have a way of telling what's supported
* for a given output format, so we try each possibility */
return ffmpeg_mux_init_context(ffm);
@ -786,7 +791,6 @@ static inline bool ffmpeg_mux_packet(struct ffmpeg_mux *ffm, uint8_t *buf,
struct ffm_packet_info *info)
{
int idx = get_index(ffm, info);
AVPacket packet = {0};
/* The muxer might not support video/audio, or multiple audio tracks */
if (idx == -1) {
@ -796,18 +800,16 @@ static inline bool ffmpeg_mux_packet(struct ffmpeg_mux *ffm, uint8_t *buf,
const AVRational codec_time_base =
get_codec_context(ffm, info)->time_base;
av_init_packet(&packet);
packet.data = buf;
packet.size = (int)info->size;
packet.stream_index = idx;
packet.pts = rescale_ts(ffm, codec_time_base, info->pts, idx);
packet.dts = rescale_ts(ffm, codec_time_base, info->dts, idx);
ffm->packet->data = buf;
ffm->packet->size = (int)info->size;
ffm->packet->stream_index = idx;
ffm->packet->pts = rescale_ts(ffm, codec_time_base, info->pts, idx);
ffm->packet->dts = rescale_ts(ffm, codec_time_base, info->dts, idx);
if (info->keyframe)
packet.flags = AV_PKT_FLAG_KEY;
ffm->packet->flags = AV_PKT_FLAG_KEY;
int ret = av_interleaved_write_frame(ffm->output, &packet);
int ret = av_interleaved_write_frame(ffm->output, ffm->packet);
if (ret < 0) {
fprintf(stderr, "av_interleaved_write_frame failed: %d: %s\n",

View File

@ -43,6 +43,8 @@ struct nvenc_encoder {
AVCodec *nvenc;
AVCodecContext *context;
AVPacket *packet;
AVFrame *vframe;
DARRAY(uint8_t) buffer;
@ -163,6 +165,8 @@ static bool nvenc_init_codec(struct nvenc_encoder *enc, bool psycho_aq)
return false;
}
enc->packet = av_packet_alloc();
enc->initialized = true;
return true;
}
@ -318,29 +322,33 @@ static bool nvenc_reconfigure(void *data, obs_data_t *settings)
return true;
}
static inline void flush_remaining_packets(struct nvenc_encoder *enc)
{
int r_pkt = 1;
while (r_pkt) {
#if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(57, 40, 101)
if (avcodec_receive_packet(enc->context, enc->packet) < 0)
break;
#else
if (avcodec_encode_video2(enc->context, enc->packet, NULL,
&r_pkt) < 0)
break;
#endif
if (r_pkt)
av_packet_unref(enc->packet);
}
}
static void nvenc_destroy(void *data)
{
struct nvenc_encoder *enc = data;
if (enc->initialized) {
AVPacket pkt = {0};
int r_pkt = 1;
while (r_pkt) {
#if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(57, 40, 101)
if (avcodec_receive_packet(enc->context, &pkt) < 0)
break;
#else
if (avcodec_encode_video2(enc->context, &pkt, NULL,
&r_pkt) < 0)
break;
#endif
if (r_pkt)
av_packet_unref(&pkt);
}
}
if (enc->initialized)
flush_remaining_packets(enc);
av_packet_free(&enc->packet);
avcodec_close(enc->context);
av_frame_unref(enc->vframe);
av_frame_free(&enc->vframe);
@ -436,26 +444,23 @@ static bool nvenc_encode(void *data, struct encoder_frame *frame,
struct encoder_packet *packet, bool *received_packet)
{
struct nvenc_encoder *enc = data;
AVPacket av_pkt = {0};
int got_packet;
int ret;
av_init_packet(&av_pkt);
copy_data(enc->vframe, frame, enc->height, enc->context->pix_fmt);
enc->vframe->pts = frame->pts;
#if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(57, 40, 101)
ret = avcodec_send_frame(enc->context, enc->vframe);
if (ret == 0)
ret = avcodec_receive_packet(enc->context, &av_pkt);
ret = avcodec_receive_packet(enc->context, enc->packet);
got_packet = (ret == 0);
if (ret == AVERROR_EOF || ret == AVERROR(EAGAIN))
ret = 0;
#else
ret = avcodec_encode_video2(enc->context, &av_pkt, enc->vframe,
ret = avcodec_encode_video2(enc->context, enc->packet, enc->vframe,
&got_packet);
#endif
if (ret < 0) {
@ -463,25 +468,27 @@ static bool nvenc_encode(void *data, struct encoder_frame *frame,
return false;
}
if (got_packet && av_pkt.size) {
if (got_packet && enc->packet->size) {
if (enc->first_packet) {
uint8_t *new_packet;
size_t size;
enc->first_packet = false;
obs_extract_avc_headers(av_pkt.data, av_pkt.size,
&new_packet, &size,
&enc->header, &enc->header_size,
&enc->sei, &enc->sei_size);
obs_extract_avc_headers(enc->packet->data,
enc->packet->size, &new_packet,
&size, &enc->header,
&enc->header_size, &enc->sei,
&enc->sei_size);
da_copy_array(enc->buffer, new_packet, size);
bfree(new_packet);
} else {
da_copy_array(enc->buffer, av_pkt.data, av_pkt.size);
da_copy_array(enc->buffer, enc->packet->data,
enc->packet->size);
}
packet->pts = av_pkt.pts;
packet->dts = av_pkt.dts;
packet->pts = enc->packet->pts;
packet->dts = enc->packet->dts;
packet->data = enc->buffer.array;
packet->size = enc->buffer.num;
packet->type = OBS_ENCODER_VIDEO;
@ -491,7 +498,7 @@ static bool nvenc_encode(void *data, struct encoder_frame *frame,
*received_packet = false;
}
av_packet_unref(&av_pkt);
av_packet_unref(enc->packet);
return true;
}

View File

@ -48,7 +48,7 @@ struct ffmpeg_output {
os_sem_t *write_sem;
os_event_t *stop_event;
DARRAY(AVPacket) packets;
DARRAY(AVPacket *) packets;
};
/* ------------------------------------------------------------------------- */
@ -740,11 +740,9 @@ static void receive_video(void *param, struct video_data *frame)
return;
AVCodecContext *context = data->video_ctx;
AVPacket packet = {0};
AVPacket *packet = NULL;
int ret = 0, got_packet;
av_init_packet(&packet);
if (!output->video_start_ts)
output->video_start_ts = frame->timestamp;
if (!data->start_timestamp)
@ -766,15 +764,19 @@ static void receive_video(void *param, struct video_data *frame)
else
copy_data(data->vframe, frame, context->height,
context->pix_fmt);
packet = av_packet_alloc();
#if LIBAVFORMAT_VERSION_MAJOR < 58
if (data->output->flags & AVFMT_RAWPICTURE) {
packet.flags |= AV_PKT_FLAG_KEY;
packet.stream_index = data->video->index;
packet.data = data->vframe->data[0];
packet.size = sizeof(AVPicture);
packet->flags |= AV_PKT_FLAG_KEY;
packet->stream_index = data->video->index;
packet->data = data->vframe->data[0];
packet->size = sizeof(AVPicture);
pthread_mutex_lock(&output->write_mutex);
da_push_back(output->packets, &packet);
packet = NULL;
pthread_mutex_unlock(&output->write_mutex);
os_sem_post(output->write_sem);
@ -784,15 +786,14 @@ static void receive_video(void *param, struct video_data *frame)
#if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(57, 40, 101)
ret = avcodec_send_frame(context, data->vframe);
if (ret == 0)
ret = avcodec_receive_packet(context, &packet);
ret = avcodec_receive_packet(context, packet);
got_packet = (ret == 0);
if (ret == AVERROR_EOF || ret == AVERROR(EAGAIN))
ret = 0;
#else
ret = avcodec_encode_video2(context, &packet, data->vframe,
&got_packet);
ret = avcodec_encode_video2(context, packet, data->vframe, &got_packet);
#endif
if (ret < 0) {
blog(LOG_WARNING,
@ -800,20 +801,21 @@ static void receive_video(void *param, struct video_data *frame)
"video: %s",
av_err2str(ret));
//FIXME: stop the encode with an error
return;
goto fail;
}
if (!ret && got_packet && packet.size) {
packet.pts = rescale_ts(packet.pts, context,
data->video->time_base);
packet.dts = rescale_ts(packet.dts, context,
data->video->time_base);
packet.duration = (int)av_rescale_q(
packet.duration, context->time_base,
if (!ret && got_packet && packet->size) {
packet->pts = rescale_ts(packet->pts, context,
data->video->time_base);
packet->dts = rescale_ts(packet->dts, context,
data->video->time_base);
packet->duration = (int)av_rescale_q(
packet->duration, context->time_base,
data->video->time_base);
pthread_mutex_lock(&output->write_mutex);
da_push_back(output->packets, &packet);
packet = NULL;
pthread_mutex_unlock(&output->write_mutex);
os_sem_post(output->write_sem);
} else {
@ -829,6 +831,9 @@ static void receive_video(void *param, struct video_data *frame)
}
data->total_frames++;
fail:
av_packet_free(&packet);
}
static void encode_audio(struct ffmpeg_output *output, int idx,
@ -836,7 +841,7 @@ static void encode_audio(struct ffmpeg_output *output, int idx,
{
struct ffmpeg_data *data = &output->ff_data;
AVPacket packet = {0};
AVPacket *packet = NULL;
int ret, got_packet;
size_t total_size = data->frame_size * block_size * context->channels;
@ -860,42 +865,48 @@ static void encode_audio(struct ffmpeg_output *output, int idx,
data->total_samples[idx] += data->frame_size;
packet = av_packet_alloc();
#if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(57, 40, 101)
ret = avcodec_send_frame(context, data->aframe[idx]);
if (ret == 0)
ret = avcodec_receive_packet(context, &packet);
ret = avcodec_receive_packet(context, packet);
got_packet = (ret == 0);
if (ret == AVERROR_EOF || ret == AVERROR(EAGAIN))
ret = 0;
#else
ret = avcodec_encode_audio2(context, &packet, data->aframe[idx],
ret = avcodec_encode_audio2(context, packet, data->aframe[idx],
&got_packet);
#endif
if (ret < 0) {
blog(LOG_WARNING, "encode_audio: Error encoding audio: %s",
av_err2str(ret));
//FIXME: stop the encode with an error
return;
goto fail;
}
if (!got_packet)
return;
goto fail;
packet.pts = rescale_ts(packet.pts, context,
data->audio_infos[idx].stream->time_base);
packet.dts = rescale_ts(packet.dts, context,
data->audio_infos[idx].stream->time_base);
packet.duration =
(int)av_rescale_q(packet.duration, context->time_base,
packet->pts = rescale_ts(packet->pts, context,
data->audio_infos[idx].stream->time_base);
packet->dts = rescale_ts(packet->dts, context,
data->audio_infos[idx].stream->time_base);
packet->duration =
(int)av_rescale_q(packet->duration, context->time_base,
data->audio_infos[idx].stream->time_base);
packet.stream_index = data->audio_infos[idx].stream->index;
packet->stream_index = data->audio_infos[idx].stream->index;
pthread_mutex_lock(&output->write_mutex);
da_push_back(output->packets, &packet);
pthread_mutex_unlock(&output->write_mutex);
os_sem_post(output->write_sem);
return;
fail:
av_packet_free(&packet);
}
/* Given a bitmask for the selected tracks and the mix index,
@ -978,7 +989,7 @@ static uint64_t get_packet_sys_dts(struct ffmpeg_output *output,
static int process_packet(struct ffmpeg_output *output)
{
AVPacket packet;
AVPacket *packet;
bool new_packet = false;
int ret;
@ -999,16 +1010,16 @@ static int process_packet(struct ffmpeg_output *output)
packet.stream_index, output->packets.num);*/
if (stopping(output)) {
uint64_t sys_ts = get_packet_sys_dts(output, &packet);
uint64_t sys_ts = get_packet_sys_dts(output, packet);
if (sys_ts >= output->stop_ts)
return 0;
}
output->total_bytes += packet.size;
output->total_bytes += packet->size;
ret = av_interleaved_write_frame(output->ff_data.output, &packet);
ret = av_interleaved_write_frame(output->ff_data.output, packet);
if (ret < 0) {
av_free_packet(&packet);
av_packet_free(&packet);
ffmpeg_log_error(LOG_WARNING, &output->ff_data,
"process_packet: Error writing packet: %s",
av_err2str(ret));
@ -1243,7 +1254,7 @@ static void ffmpeg_deactivate(struct ffmpeg_output *output)
pthread_mutex_lock(&output->write_mutex);
for (size_t i = 0; i < output->packets.num; i++)
av_free_packet(output->packets.array + i);
av_packet_free(output->packets.array + i);
da_free(output->packets);
pthread_mutex_unlock(&output->write_mutex);

View File

@ -57,6 +57,8 @@ struct vaapi_encoder {
AVCodec *vaapi;
AVCodecContext *context;
AVPacket *packet;
AVFrame *vframe;
DARRAY(uint8_t) buffer;
@ -159,6 +161,8 @@ static bool vaapi_init_codec(struct vaapi_encoder *enc, const char *path)
return false;
}
enc->packet = av_packet_alloc();
enc->initialized = true;
return true;
}
@ -298,29 +302,33 @@ static bool vaapi_update(void *data, obs_data_t *settings)
return vaapi_init_codec(enc, device);
}
static inline void flush_remaining_packets(struct vaapi_encoder *enc)
{
int r_pkt = 1;
while (r_pkt) {
#if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(57, 40, 101)
if (avcodec_receive_packet(enc->context, enc->packet) < 0)
break;
#else
if (avcodec_encode_video2(enc->context, enc->packet, NULL,
&r_pkt) < 0)
break;
#endif
if (r_pkt)
av_packet_unref(enc->packet);
}
}
static void vaapi_destroy(void *data)
{
struct vaapi_encoder *enc = data;
if (enc->initialized) {
AVPacket pkt = {0};
int r_pkt = 1;
while (r_pkt) {
#if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(57, 40, 101)
if (avcodec_receive_packet(enc->context, &pkt) < 0)
break;
#else
if (avcodec_encode_video2(enc->context, &pkt, NULL,
&r_pkt) < 0)
break;
#endif
if (r_pkt)
av_packet_unref(&pkt);
}
}
if (enc->initialized)
flush_remaining_packets(enc);
av_packet_free(&enc->packet);
avcodec_close(enc->context);
av_frame_unref(enc->vframe);
av_frame_free(&enc->vframe);
@ -405,7 +413,6 @@ static bool vaapi_encode(void *data, struct encoder_frame *frame,
{
struct vaapi_encoder *enc = data;
AVFrame *hwframe = NULL;
AVPacket av_pkt;
int got_packet;
int ret;
@ -443,19 +450,17 @@ static bool vaapi_encode(void *data, struct encoder_frame *frame,
goto fail;
}
av_init_packet(&av_pkt);
#if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(57, 40, 101)
ret = avcodec_send_frame(enc->context, hwframe);
if (ret == 0)
ret = avcodec_receive_packet(enc->context, &av_pkt);
ret = avcodec_receive_packet(enc->context, enc->packet);
got_packet = (ret == 0);
if (ret == AVERROR_EOF || ret == AVERROR(EAGAIN))
ret = 0;
#else
ret = avcodec_encode_video2(enc->context, &av_pkt, hwframe,
ret = avcodec_encode_video2(enc->context, enc->packet, hwframe,
&got_packet);
#endif
if (ret < 0) {
@ -463,25 +468,27 @@ static bool vaapi_encode(void *data, struct encoder_frame *frame,
goto fail;
}
if (got_packet && av_pkt.size) {
if (got_packet && enc->packet->size) {
if (enc->first_packet) {
uint8_t *new_packet;
size_t size;
enc->first_packet = false;
obs_extract_avc_headers(av_pkt.data, av_pkt.size,
&new_packet, &size,
&enc->header, &enc->header_size,
&enc->sei, &enc->sei_size);
obs_extract_avc_headers(enc->packet->data,
enc->packet->size, &new_packet,
&size, &enc->header,
&enc->header_size, &enc->sei,
&enc->sei_size);
da_copy_array(enc->buffer, new_packet, size);
bfree(new_packet);
} else {
da_copy_array(enc->buffer, av_pkt.data, av_pkt.size);
da_copy_array(enc->buffer, enc->packet->data,
enc->packet->size);
}
packet->pts = av_pkt.pts;
packet->dts = av_pkt.dts;
packet->pts = enc->packet->pts;
packet->dts = enc->packet->dts;
packet->data = enc->buffer.array;
packet->size = enc->buffer.num;
packet->type = OBS_ENCODER_VIDEO;
@ -491,7 +498,7 @@ static bool vaapi_encode(void *data, struct encoder_frame *frame,
*received_packet = false;
}
av_packet_unref(&av_pkt);
av_packet_unref(enc->packet);
av_frame_free(&hwframe);
return true;

View File

@ -225,7 +225,6 @@ bool ffmpeg_decode_audio(struct ffmpeg_decode *decode, uint8_t *data,
size_t size, struct obs_source_audio *audio,
bool *got_output)
{
AVPacket packet = {0};
int got_frame = false;
int ret = 0;
@ -233,18 +232,21 @@ bool ffmpeg_decode_audio(struct ffmpeg_decode *decode, uint8_t *data,
copy_data(decode, data, size);
av_init_packet(&packet);
packet.data = decode->packet_buffer;
packet.size = (int)size;
if (!decode->frame) {
decode->frame = av_frame_alloc();
if (!decode->frame)
return false;
}
if (data && size)
ret = avcodec_send_packet(decode->decoder, &packet);
if (data && size) {
AVPacket *packet = av_packet_alloc();
packet->data = decode->packet_buffer;
packet->size = (int)size;
ret = avcodec_send_packet(decode->decoder, packet);
av_packet_free(&packet);
}
if (ret == 0)
ret = avcodec_receive_frame(decode->decoder, decode->frame);
@ -297,7 +299,6 @@ bool ffmpeg_decode_video(struct ffmpeg_decode *decode, uint8_t *data,
enum video_range_type range,
struct obs_source_frame2 *frame, bool *got_output)
{
AVPacket packet = {0};
int got_frame = false;
AVFrame *out_frame;
int ret;
@ -306,15 +307,6 @@ bool ffmpeg_decode_video(struct ffmpeg_decode *decode, uint8_t *data,
copy_data(decode, data, size);
av_init_packet(&packet);
packet.data = decode->packet_buffer;
packet.size = (int)size;
packet.pts = *ts;
if (decode->codec->id == AV_CODEC_ID_H264 &&
obs_avc_keyframe(data, size))
packet.flags |= AV_PKT_FLAG_KEY;
if (!decode->frame) {
decode->frame = av_frame_alloc();
if (!decode->frame)
@ -329,11 +321,22 @@ bool ffmpeg_decode_video(struct ffmpeg_decode *decode, uint8_t *data,
out_frame = decode->hw ? decode->hw_frame : decode->frame;
ret = avcodec_send_packet(decode->decoder, &packet);
AVPacket *packet = av_packet_alloc();
packet->data = decode->packet_buffer;
packet->size = (int)size;
packet->pts = *ts;
if (decode->codec->id == AV_CODEC_ID_H264 &&
obs_avc_keyframe(data, size))
packet->flags |= AV_PKT_FLAG_KEY;
ret = avcodec_send_packet(decode->decoder, packet);
if (ret == 0) {
ret = avcodec_receive_frame(decode->decoder, out_frame);
}
av_packet_free(&packet);
got_frame = (ret == 0);
if (ret == AVERROR_EOF || ret == AVERROR(EAGAIN))