diff --git a/plugins/obs-ffmpeg/ffmpeg-mux/ffmpeg-mux.c b/plugins/obs-ffmpeg/ffmpeg-mux/ffmpeg-mux.c index 59dcf0401..e6f4b0f87 100644 --- a/plugins/obs-ffmpeg/ffmpeg-mux/ffmpeg-mux.c +++ b/plugins/obs-ffmpeg/ffmpeg-mux/ffmpeg-mux.c @@ -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", diff --git a/plugins/obs-ffmpeg/obs-ffmpeg-nvenc.c b/plugins/obs-ffmpeg/obs-ffmpeg-nvenc.c index e66010ce5..992110c1e 100644 --- a/plugins/obs-ffmpeg/obs-ffmpeg-nvenc.c +++ b/plugins/obs-ffmpeg/obs-ffmpeg-nvenc.c @@ -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; } diff --git a/plugins/obs-ffmpeg/obs-ffmpeg-output.c b/plugins/obs-ffmpeg/obs-ffmpeg-output.c index 7d1f12a60..45cc331db 100644 --- a/plugins/obs-ffmpeg/obs-ffmpeg-output.c +++ b/plugins/obs-ffmpeg/obs-ffmpeg-output.c @@ -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); diff --git a/plugins/obs-ffmpeg/obs-ffmpeg-vaapi.c b/plugins/obs-ffmpeg/obs-ffmpeg-vaapi.c index 1598d39db..22f0f0950 100644 --- a/plugins/obs-ffmpeg/obs-ffmpeg-vaapi.c +++ b/plugins/obs-ffmpeg/obs-ffmpeg-vaapi.c @@ -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; diff --git a/plugins/win-dshow/ffmpeg-decode.c b/plugins/win-dshow/ffmpeg-decode.c index 15f00c4d0..cdc578e2b 100644 --- a/plugins/win-dshow/ffmpeg-decode.c +++ b/plugins/win-dshow/ffmpeg-decode.c @@ -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))