ffmpeg视频编码及封装

#include <stdio.h>
#include <libavcodec/avcodec.h>
//#include <libavutil/time.h>
#include <libavformat/avformat.h>


static void encode(AVCodecContext *enc_ctx, AVFrame *frame, AVPacket *pkt,
                   AVFormatContext *oc)
{
    int ret;
    ret = avcodec_send_frame(enc_ctx, frame);
    if (ret < 0) {
        fprintf(stderr, "Error sending a frame for encoding\n");
        exit(1);
    }
    while (ret >= 0) {
        ret = avcodec_receive_packet(enc_ctx, pkt);
        if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
            return;
        else if (ret < 0) {
            fprintf(stderr, "Error during encoding\n");
            exit(1);
        }
        //printf("Write packet %3"PRId64" (size=%5d)\n", pkt->pts, pkt->size);
        //fwrite(pkt->data, 1, pkt->size, outfile)
        ;
        //将编码后的帧写入文件
		av_interleaved_write_frame(oc, pkt);
        av_packet_unref(pkt);
    }
}

int main(int argc, char* argv[])
{
    const char *ifile = "./test/clip.yuv";
    const char *ofile = "111.ts";
    int bitrate = 5000000;
    int width = 1280;
    int height = 720;
    int fps = 30;
    int ret = -1;
    unsigned int read_size;
    int64_t start_time;
    
    AVCodec* codec;
    AVFrame *frame;
    AVPacket *pkt;
    AVCodecContext *codec_ctx;
    ///
    AVFormatContext *oc = NULL;
    
    
    FILE *input_fp = fopen(ifile, "rb");
    if (input_fp == NULL)
    {
      fprintf(stderr, "Could not to open inputfile.\n");
      return -1;
    }
    
    // output_fp = fopen("./clip2.ts", "wb");
    // if (!output_fp )
    // {
    //   fprintf(stderr, "Could not open outputfile.\n");
    //   return -1;
    // }
    
    fseek(input_fp, 0, SEEK_END);
    unsigned int infile_size = ftell(input_fp);
    unsigned int frame_cnt = infile_size / (width*height*3/2);
    printf("frame_cnt frame_cnt %3d \n", frame_cnt);

    codec = avcodec_find_encoder_by_name("libxvid");
    if (!codec) {
        fprintf(stderr,"Codec not found\n");
        return -1;
    }

    codec_ctx = avcodec_alloc_context3(codec);
    if (!codec_ctx) {
        fprintf(stderr,"Could not allocate video codec context\n");
        return -1;
    }
    
    codec_ctx->bit_rate = bitrate;
    codec_ctx->width = width;
    codec_ctx->height = height;
    codec_ctx->time_base = (AVRational){1, fps};
    codec_ctx->framerate = (AVRational){fps, 1};
    //codec_ctx->gop_size = 4;
    codec_ctx->max_b_frames = 2;
    codec_ctx->pix_fmt = AV_PIX_FMT_YUV420P;

    
    //av_opt_set(codec_ctx->priv_data, "preset", "slow", 0);
        
    ret = avcodec_open2(codec_ctx, codec, NULL);
    if (ret < 0) {
        fprintf(stderr,"Could not open codec: %s\n", av_err2str(ret));
        return -1;
    }

    /
    //2 create out context
	avformat_alloc_output_context2(&oc, 0, 0, ofile);
 
	//3 add video stream
	AVStream *st = avformat_new_stream(oc, NULL);
	st->id = 0;
	st->codecpar->codec_tag = 0;
    avcodec_parameters_from_context(st->codecpar, codec_ctx);

    av_dump_format(oc, 0, ofile, 1);

    //5 write mp4 head
	ret = avio_open(&oc->pb, ofile, AVIO_FLAG_WRITE);
	if (ret < 0)
	{
		fprintf(stderr," avio_open  failed! \n");
		getchar();
		return -1;
	}
	ret = avformat_write_header(oc, NULL);
	if (ret < 0)
	{
		fprintf(stderr," avformat_write_header  failed! \n");
		getchar();
		return -1;
	}

    /

    frame = av_frame_alloc();
    if (!frame) {
        fprintf(stderr,"Could not allocate video frame\n");
        return -1;
    }
    frame->format = codec_ctx->pix_fmt;
    frame->width  = codec_ctx->width;
    frame->height = codec_ctx->height;
	
    ret = av_frame_get_buffer(frame, 32);
    if (ret < 0) {
        fprintf(stderr, "Could not allocate the video frame data\n");
        return -1;
    }

    pkt = av_packet_alloc();
    if (!pkt) {
        return -1;
    }
    
    //start_time = av_gettime_relative();
    fseek(input_fp, 0, SEEK_SET);
    // Loop over all frames in inputfile
    int i, j;
    for (i = 0; i < frame_cnt; i++)
    {
        // Make sure the frame data is writable
        int rc = av_frame_make_writable(frame);
        if (rc < 0)
        {
          fprintf(stderr, "av_frame_make_writable() error.\n");
          return -1;
        }

        // Read data for Y into frame buffer
        for (j = 0; j < codec_ctx->height; j++)
        {
          read_size = fread(&frame->data[0][0] + j * frame->linesize[0], codec_ctx->width, 1, input_fp);
          if (read_size != 1) {
            fprintf(stderr, "Failed to read Y. read_size=%u.\n", read_size);
            return -1;
          }
        }
        // Read data for U into frame buffer
        for (j = 0; j < codec_ctx->height / 2; j++)
        {
          read_size = fread(&frame->data[1][0] + j * frame->linesize[1], codec_ctx->width / 2, 1, input_fp);
          if (read_size != 1) {
            fprintf(stderr, "Failed to read U. read_size=%u.\n", read_size);
            return -1;
          }
        }
        // Read data for V into frame buffer
        for (j = 0; j < codec_ctx->height / 2; j++)
        {
          read_size = fread(&frame->data[2][0] + j * frame->linesize[2], codec_ctx->width / 2, 1, input_fp);
          if (read_size != 1)
          {
            fprintf(stderr, "Failed to read V. read_size=%u.\n", read_size);
            return -1;
          }
        }

        frame->pts = i * 90000 / fps;
        
        // Encode frame
        encode(codec_ctx, frame, pkt, oc);
        //print_report(0, start_time, av_gettime_relative(), i);
    }
    
    //sleep(2);
    encode(codec_ctx, NULL, pkt, oc);
    //print_report(0, start_time, av_gettime_relative(), frame_cnt);

    //写文件尾
	av_write_trailer(oc);
 
	//关闭视频输出IO
	avio_close(oc->pb);
 
	//清理封装输出上下文
	avformat_free_context(oc);

    //fclose(output_fp);
    fclose(input_fp);
    //清理编码器上下文
    avcodec_free_context(&codec_ctx);
    av_frame_free(&frame);
    av_packet_free(&pkt);
    
    return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
FFmpeg是一个开源的多媒体框架,它提供了许多对音视频的处理、编解码、封装等功能的API接口。下面是关于FFmpeg封装编码接口的介绍。 封装接口 FFmpeg封装的主要作用是将音视频数据打包成一个容器格式,例如AVI、MP4、MKV等。在FFmpeg中,封装的主要接口是AVFormatContext。通过AVFormatContext可以设置封装格式、音视频流的参数、写入数据等。 下面是一个简单的示例代码: ``` AVFormatContext *fmt_ctx = NULL; avformat_alloc_output_context2(&fmt_ctx, NULL, NULL, filename); if (!fmt_ctx) { // error handling } // 添加视频流 AVStream *video_stream = avformat_new_stream(fmt_ctx, NULL); if (!video_stream) { // error handling } video_stream->codecpar->codec_id = AV_CODEC_ID_H264; video_stream->codecpar->width = width; video_stream->codecpar->height = height; video_stream->codecpar->format = AV_PIX_FMT_YUV420P; // 添加音频流 AVStream *audio_stream = avformat_new_stream(fmt_ctx, NULL); if (!audio_stream) { // error handling } audio_stream->codecpar->codec_id = AV_CODEC_ID_AAC; audio_stream->codecpar->sample_rate = sample_rate; audio_stream->codecpar->channels = channels; audio_stream->codecpar->channel_layout = av_get_default_channel_layout(channels); // 打开输出文件 avio_open(&fmt_ctx->pb, filename, AVIO_FLAG_WRITE); avformat_write_header(fmt_ctx, NULL); // 写入数据 AVPacket pkt = { 0 }; av_init_packet(&pkt); // 写入视频数据 avcodec_send_frame(video_codec_ctx, frame); while (avcodec_receive_packet(video_codec_ctx, &pkt) == 0) { av_write_frame(fmt_ctx, &pkt); av_packet_unref(&pkt); } // 写入音频数据 avcodec_send_frame(audio_codec_ctx, frame); while (avcodec_receive_packet(audio_codec_ctx, &pkt) == 0) { av_write_frame(fmt_ctx, &pkt); av_packet_unref(&pkt); } // 关闭输出文件 av_write_trailer(fmt_ctx); avformat_free_context(fmt_ctx); ``` 在上面的代码中,我们首先创建了一个AVFormatContext对象,并设置了要输出的文件名和封装格式。然后,我们添加了一个视频流和一个音频流,并设置了它们的参数。接着,我们打开了输出文件,并使用avformat_write_header()函数写入文件头。最后,我们使用av_write_frame()函数将编码后的数据写入文件,并使用av_write_trailer()函数结束文件的写入。 编码接口 FFmpeg的编码接口主要用于将原始音视频数据编码成压缩格式,例如H.264、AAC等。在FFmpeg中,编码的主要接口是AVCodecContext。通过AVCodecContext可以设置编码器类型、编码参数、输入数据等。 下面是一个简单的示例代码: ``` AVCodec *codec = avcodec_find_encoder(AV_CODEC_ID_H264); if (!codec) { // error handling } AVCodecContext *codec_ctx = avcodec_alloc_context3(codec); if (!codec_ctx) { // error handling } codec_ctx->width = width; codec_ctx->height = height; codec_ctx->framerate = { fps, 1 }; codec_ctx->pix_fmt = AV_PIX_FMT_YUV420P; codec_ctx->time_base = { 1, fps }; codec_ctx->gop_size = 10; codec_ctx->bit_rate = 1000000; avcodec_open2(codec_ctx, codec, NULL); AVFrame *frame = av_frame_alloc(); if (!frame) { // error handling } frame->width = width; frame->height = height; frame->format = AV_PIX_FMT_YUV420P; av_frame_get_buffer(frame, 0); AVPacket pkt = { 0 }; av_init_packet(&pkt); // 填充视频帧数据 ... avcodec_send_frame(codec_ctx, frame); while (avcodec_receive_packet(codec_ctx, &pkt) == 0) { // 处理编码后的数据 av_packet_unref(&pkt); } ``` 在上面的代码中,我们首先使用avcodec_find_encoder()函数查找H.264编码器。然后,我们创建了一个AVCodecContext对象,并设置了编码器的参数。接着,我们使用avcodec_open2()函数打开编码器。接下来,我们创建了一个AVFrame对象,并使用av_frame_get_buffer()函数分配内存。最后,我们使用avcodec_send_frame()函数将原始数据发送给编码器,并使用avcodec_receive_packet()函数获取编码后的数据。 总结 FFmpeg提供了许多封装、编码、解码等功能的API接口,可以方便地进行音视频处理。在使用FFmpeg进行封装编码时,需要了解AVFormatContext和AVCodecContext等对象的使用方法,并根据具体的需求进行参数的设置。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值