FFmpeg API 接收H264/265的码流代码示例
时间: 2023-10-08 10:09:26 浏览: 234
以下是一个简单的示例代码,展示如何使用FFmpeg API接收H.264/H.265的码流:
```c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavutil/imgutils.h>
#include <libswscale/swscale.h>
int main(int argc, char **argv) {
if (argc < 2) {
fprintf(stderr, "Usage: %s <input file>\n", argv[0]);
exit(1);
}
const char *input_filename = argv[1];
AVFormatContext *input_format_ctx = NULL;
int ret = avformat_open_input(&input_format_ctx, input_filename, NULL, NULL);
if (ret < 0) {
fprintf(stderr, "Error: Failed to open input file: %s\n", av_err2str(ret));
exit(1);
}
ret = avformat_find_stream_info(input_format_ctx, NULL);
if (ret < 0) {
fprintf(stderr, "Error: Failed to retrieve input stream information: %s\n", av_err2str(ret));
exit(1);
}
int video_stream_index = -1;
for (int i = 0; i < input_format_ctx->nb_streams; i++) {
AVStream *stream = input_format_ctx->streams[i];
if (stream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
video_stream_index = i;
break;
}
}
if (video_stream_index == -1) {
fprintf(stderr, "Error: Failed to find video stream in input file\n");
exit(1);
}
AVCodecParameters *codec_params = input_format_ctx->streams[video_stream_index]->codecpar;
AVCodec *codec = avcodec_find_decoder(codec_params->codec_id);
if (!codec) {
fprintf(stderr, "Error: Failed to find codec for input stream\n");
exit(1);
}
AVCodecContext *codec_ctx = avcodec_alloc_context3(codec);
if (!codec_ctx) {
fprintf(stderr, "Error: Failed to allocate codec context\n");
exit(1);
}
ret = avcodec_parameters_to_context(codec_ctx, codec_params);
if (ret < 0) {
fprintf(stderr, "Error: Failed to copy codec parameters to codec context: %s\n", av_err2str(ret));
exit(1);
}
ret = avcodec_open2(codec_ctx, codec, NULL);
if (ret < 0) {
fprintf(stderr, "Error: Failed to open codec: %s\n", av_err2str(ret));
exit(1);
}
AVPacket *packet = av_packet_alloc();
if (!packet) {
fprintf(stderr, "Error: Failed to allocate packet\n");
exit(1);
}
AVFrame *frame = av_frame_alloc();
if (!frame) {
fprintf(stderr, "Error: Failed to allocate frame\n");
exit(1);
}
AVFrame *frame_rgb = av_frame_alloc();
if (!frame_rgb) {
fprintf(stderr, "Error: Failed to allocate RGB frame\n");
exit(1);
}
int num_bytes = av_image_get_buffer_size(AV_PIX_FMT_RGB24, codec_ctx->width, codec_ctx->height, 1);
uint8_t *buffer = (uint8_t *) av_malloc(num_bytes * sizeof(uint8_t));
if (!buffer) {
fprintf(stderr, "Error: Failed to allocate buffer\n");
exit(1);
}
ret = av_image_fill_arrays(frame_rgb->data, frame_rgb->linesize, buffer, AV_PIX_FMT_RGB24, codec_ctx->width, codec_ctx->height, 1);
if (ret < 0) {
fprintf(stderr, "Error: Failed to fill image arrays: %s\n", av_err2str(ret));
exit(1);
}
struct SwsContext *sws_ctx = sws_getContext(codec_ctx->width, codec_ctx->height, codec_ctx->pix_fmt, codec_ctx->width, codec_ctx->height, AV_PIX_FMT_RGB24, 0, NULL, NULL, NULL);
if (!sws_ctx) {
fprintf(stderr, "Error: Failed to create scaling context\n");
exit(1);
}
while (av_read_frame(input_format_ctx, packet) >= 0) {
if (packet->stream_index != video_stream_index) {
av_packet_unref(packet);
continue;
}
ret = avcodec_send_packet(codec_ctx, packet);
if (ret < 0) {
fprintf(stderr, "Error: Failed to send packet to codec: %s\n", av_err2str(ret));
exit(1);
}
while (ret >= 0) {
ret = avcodec_receive_frame(codec_ctx, frame);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
break;
}
if (ret < 0) {
fprintf(stderr, "Error: Failed to receive frame from codec: %s\n", av_err2str(ret));
exit(1);
}
sws_scale(sws_ctx, (const uint8_t *const *) frame->data, frame->linesize, 0, codec_ctx->height, frame_rgb->data, frame_rgb->linesize);
// Do something with the RGB frame here
}
av_packet_unref(packet);
}
avformat_close_input(&input_format_ctx);
avcodec_free_context(&codec_ctx);
av_frame_free(&frame);
av_frame_free(&frame_rgb);
av_packet_free(&packet);
sws_freeContext(sws_ctx);
av_free(buffer);
return 0;
}
```
此代码打开一个H.264/H.265视频文件,查找视频流,获取解码器并打开它。然后,它循环读取视频帧并将其解码为RGB格式。您可以在 `sws_scale` 函数之后添加自己的代码,以处理RGB帧。最后,它清理所有的FFmpeg上下文和分配的内存。
阅读全文