// 获取AVFrame用来保存解码出来的yuv数据 AVFrame* decodingFrame = m_frames->decodingFrame(); // 解码 int ret; // 解码h264 if ((ret = avcodec_send_packet(codecCtx, &packet)) < 0) { qCritical("Could not send video packet: %d", ret); goto runQuit; } // 取出yuv if (decodingFrame) { ret = avcodec_receive_frame(codecCtx, decodingFrame); }内存泄露怎么解决
时间: 2024-01-21 09:04:53 浏览: 120
要解决内存泄漏问题,你需要在使用完 AVFrame 后手动释放它占用的内存。你可以通过调用 `av_frame_unref()` 函数来释放 AVFrame 对象的内存,该函数会将 AVFrame 中的所有缓冲区引用计数减一,如果引用计数归零,则会自动释放对应的内存。
在你的代码中,可以在使用完 decodingFrame 后调用 `av_frame_unref(decodingFrame)` 来释放它占用的内存。例如:
```
// 取出yuv
if (decodingFrame) {
ret = avcodec_receive_frame(codecCtx, decodingFrame);
// 处理解码出来的yuv数据
...
// 释放AVFrame占用的内存
av_frame_unref(decodingFrame);
}
```
这样就可以避免 AVFrame 对象的内存泄漏问题。
相关问题
MP4视频通过mediacode并使用C++语言解码成yuv数据
好的,你可以使用C++语言结合FFmpeg库来解码MP4视频文件并将其转换成YUV数据。以下是一个基本的示例代码,你可以根据自己的需要进行调整和修改:
```c++
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <stdint.h>
// FFmpeg头文件
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
void decode(const char* filename, const char* outfilename) {
// 初始化FFmpeg库
av_register_all();
// 打开输入文件
AVFormatContext* format_ctx = NULL;
if (avformat_open_input(&format_ctx, filename, NULL, NULL) != 0) {
fprintf(stderr, "Error: Failed to open input file\n");
return;
}
// 获取流信息
if (avformat_find_stream_info(format_ctx, NULL) < 0) {
fprintf(stderr, "Error: Failed to find stream information\n");
avformat_close_input(&format_ctx);
return;
}
// 找到视频流
int video_stream_index = -1;
for (int i = 0; i < format_ctx->nb_streams; i++) {
if (format_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
video_stream_index = i;
break;
}
}
if (video_stream_index == -1) {
fprintf(stderr, "Error: Failed to find video stream\n");
avformat_close_input(&format_ctx);
return;
}
// 获取视频解码器
AVCodecParameters* codec_params = format_ctx->streams[video_stream_index]->codecpar;
AVCodec* codec = avcodec_find_decoder(codec_params->codec_id);
AVCodecContext* codec_ctx = avcodec_alloc_context3(codec);
if (avcodec_parameters_to_context(codec_ctx, codec_params) < 0) {
fprintf(stderr, "Error: Failed to copy codec parameters to decoder context\n");
avcodec_free_context(&codec_ctx);
avformat_close_input(&format_ctx);
return;
}
if (avcodec_open2(codec_ctx, codec, NULL) < 0) {
fprintf(stderr, "Error: Failed to open codec\n");
avcodec_free_context(&codec_ctx);
avformat_close_input(&format_ctx);
return;
}
// 打开输出文件
FILE* outfile = fopen(outfilename, "wb");
if (!outfile) {
fprintf(stderr, "Error: Failed to open output file\n");
avcodec_free_context(&codec_ctx);
avformat_close_input(&format_ctx);
return;
}
// 初始化视频帧
AVFrame* frame = av_frame_alloc();
AVPacket pkt;
av_init_packet(&pkt);
pkt.data = NULL;
pkt.size = 0;
// 读取视频帧并转换为YUV数据
int frame_count = 0;
while (av_read_frame(format_ctx, &pkt) >= 0) {
if (pkt.stream_index == video_stream_index) {
int ret = avcodec_send_packet(codec_ctx, &pkt);
while (ret >= 0) {
ret = avcodec_receive_frame(codec_ctx, frame);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
break;
} else if (ret < 0) {
fprintf(stderr, "Error: Failed to decode frame\n");
goto end;
}
// 转换为YUV数据并写入输出文件
fwrite(frame->data[0], 1, frame->linesize[0] * codec_ctx->height, outfile);
fwrite(frame->data[1], 1, frame->linesize[1] * codec_ctx->height / 2, outfile);
fwrite(frame->data[2], 1, frame->linesize[2] * codec_ctx->height / 2, outfile);
frame_count++;
}
}
av_packet_unref(&pkt);
}
// 输出解码帧的数量
printf("Decoded %d frames\n", frame_count);
end:
av_frame_free(&frame);
avcodec_free_context(&codec_ctx);
avformat_close_input(&format_ctx);
fclose(outfile);
}
int main(int argc, char* argv[]) {
if (argc < 3) {
fprintf(stderr, "Usage: %s <input_file> <output_file>\n", argv[0]);
return 1;
}
decode(argv[1], argv[2]);
return 0;
}
```
这个示例代码会将指定的MP4视频文件解码为YUV数据,并将YUV数据写入到指定的输出文件中。你可以使用这个代码作为参考,根据自己的需求进行修改和扩展。请确保在使用代码前正确安装并配置好FFmpeg库。
ffmpeg 编码yuv数据保存文件
要将 YUV 数据编码为视频文件,可以使用 ffmpeg 库提供的 API。以下是一个简单的示例代码:
```c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <libavutil/imgutils.h>
#include <libavutil/opt.h>
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
int main(int argc, char *argv[]) {
int ret = 0;
AVFormatContext *format_ctx = NULL;
AVOutputFormat *output_fmt = NULL;
AVStream *video_stream = NULL;
AVCodec *codec = NULL;
AVCodecContext *codec_ctx = NULL;
AVPacket pkt = { 0 };
int video_frame_count = 0;
int video_width = 640;
int video_height = 480;
int video_fps = 25;
const char *output_filename = "output.mp4";
// 初始化 FFmpeg 库
av_register_all();
// 打开输出文件
ret = avformat_alloc_output_context2(&format_ctx, NULL, NULL, output_filename);
if (ret < 0) {
fprintf(stderr, "Failed to allocate output format context: %s\n", av_err2str(ret));
return ret;
}
output_fmt = format_ctx->oformat;
// 添加视频流
codec = avcodec_find_encoder(output_fmt->video_codec);
if (!codec) {
fprintf(stderr, "Failed to find video encoder\n");
ret = AVERROR(EINVAL);
goto end;
}
video_stream = avformat_new_stream(format_ctx, codec);
if (!video_stream) {
fprintf(stderr, "Failed to create video stream\n");
ret = AVERROR(EINVAL);
goto end;
}
codec_ctx = avcodec_alloc_context3(codec);
if (!codec_ctx) {
fprintf(stderr, "Failed to allocate codec context\n");
ret = AVERROR(ENOMEM);
goto end;
}
codec_ctx->width = video_width;
codec_ctx->height = video_height;
codec_ctx->pix_fmt = AV_PIX_FMT_YUV420P;
codec_ctx->time_base = (AVRational) { 1, video_fps };
codec_ctx->framerate = (AVRational) { video_fps, 1 };
codec_ctx->gop_size = 10;
codec_ctx->max_b_frames = 1;
codec_ctx->bit_rate = 400000;
codec_ctx->rc_min_rate = codec_ctx->rc_max_rate = codec_ctx->bit_rate;
codec_ctx->sample_aspect_ratio = (AVRational) { 1, 1 };
if (format_ctx->oformat->flags & AVFMT_GLOBALHEADER)
codec_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
ret = avcodec_open2(codec_ctx, codec, NULL);
if (ret < 0) {
fprintf(stderr, "Failed to open video encoder: %s\n", av_err2str(ret));
goto end;
}
ret = avcodec_parameters_from_context(video_stream->codecpar, codec_ctx);
if (ret < 0) {
fprintf(stderr, "Failed to copy codec parameters: %s\n", av_err2str(ret));
goto end;
}
av_dump_format(format_ctx, 0, output_filename, 1);
// 打开输出文件并写文件头
ret = avio_open(&format_ctx->pb, output_filename, AVIO_FLAG_WRITE);
if (ret < 0) {
fprintf(stderr, "Failed to open output file: %s\n", av_err2str(ret));
goto end;
}
ret = avformat_write_header(format_ctx, NULL);
if (ret < 0) {
fprintf(stderr, "Failed to write file header: %s\n", av_err2str(ret));
goto end;
}
// 编码 YUV 数据并写入文件
int y_size = video_width * video_height;
int uv_size = y_size / 4;
uint8_t *y_data = (uint8_t *) malloc(y_size);
uint8_t *u_data = (uint8_t *) malloc(uv_size);
uint8_t *v_data = (uint8_t *) malloc(uv_size);
for (int i = 0; i < 300; i++) {
// 生成测试数据
for (int j = 0; j < y_size; j++) {
y_data[j] = i % 255;
}
for (int j = 0; j < uv_size; j++) {
u_data[j] = (i + j) % 255;
v_data[j] = (i + j + uv_size) % 255;
}
// 将 YUV 数据填充到 AVFrame 中
AVFrame *frame = av_frame_alloc();
frame->width = video_width;
frame->height = video_height;
frame->format = AV_PIX_FMT_YUV420P;
av_image_fill_arrays(frame->data, frame->linesize, y_data, video_width, u_data, video_width / 2, v_data, video_width / 2, AV_PIX_FMT_YUV420P, 1);
// 编码 AVFrame 并写入文件
ret = avcodec_send_frame(codec_ctx, frame);
if (ret < 0) {
fprintf(stderr, "Error sending frame: %s\n", av_err2str(ret));
av_frame_free(&frame);
goto end;
}
while (ret >= 0) {
ret = avcodec_receive_packet(codec_ctx, &pkt);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
break;
} else if (ret < 0) {
fprintf(stderr, "Error receiving packet: %s\n", av_err2str(ret));
goto end;
}
pkt.stream_index = video_stream->index;
av_packet_rescale_ts(&pkt, codec_ctx->time_base, video_stream->time_base);
pkt.pts = video_frame_count * video_stream->time_base.den / (video_stream->time_base.num * video_fps);
pkt.dts = pkt.pts;
pkt.duration = video_stream->time_base.den / (video_stream->time_base.num * video_fps);
pkt.pos = -1;
av_interleaved_write_frame(format_ctx, &pkt);
av_packet_unref(&pkt);
}
av_frame_free(&frame);
video_frame_count++;
}
// 写文件尾并释放资源
av_write_trailer(format_ctx);
end:
if (codec_ctx) {
avcodec_free_context(&codec_ctx);
}
if (format_ctx) {
if (format_ctx->pb) {
avio_closep(&format_ctx->pb);
}
avformat_free_context(format_ctx);
}
if (ret < 0) {
fprintf(stderr, "Error occurred: %s\n", av_err2str(ret));
return 1;
}
return 0;
}
```
在这个示例代码中,我们首先使用 avformat_alloc_output_context2 函数创建一个 AVFormatContext 对象,然后使用 avformat_new_stream 函数为该对象添加一个视频流。接着,我们使用 AVCodecContext 结构体设置了视频流的一些参数,例如分辨率、帧率、编码格式等。然后,我们使用 avcodec_open2 函数打开了该编码器,并使用 avcodec_parameters_from_context 函数将编码器参数复制到视频流的 codecpar 结构体中。最后,我们打开输出文件并写入文件头,然后循环编码 YUV 数据并将编码后的数据写入文件中,最后写入文件尾并释放资源。
需要注意的是,在编码每一帧数据时,我们需要将 AVFrame 转换成编码器所需的格式,并使用 avcodec_send_frame 函数发送该 AVFrame,然后使用 avcodec_receive_packet 函数接收编码器编码后的数据。在将编码后的数据写入文件前,需要将编码后的时间戳 PTS 和 DTS 进行适当的转换和设置。
阅读全文