C+ffmpeg从媒体文件mkv提取h264码流源码

【版权申明】转载请附上出处链接

C+ffmpeg从媒体文件mkv提取h264码流源码

编译指令:

$gcc extr_video.c -lavcodec -lavformat -lavutil -lswscale -o extr_video

包含的头文件:

#include <stdio.h>
#include <libavutil/log.h>
#include <libavformat/avio.h>
#include <libavformat/avformat.h>

宏或函数的说明:

/**
 * @macro	在p地址处放置一个4字节的val
 */
AV_WB32(p, val)

/**
 * @function	扩充Packet的大小
 * 
 * @param out	需要被扩充的packet的指针
 * @param in	data,在完成扩充后被复制到packet的data中
 * @param in_size	data的大小
 * 
 * @return	成功则返回零
 */
static int alloc_and_copy(AVPacket *out,const uint8_t *in, uint32_t in_size)

/**
 * @function	处理拿通过av_read_frame()拿到的packet,然后输出到h264的码流文件中
 * 
 * @param in	通过av_read_frame()拿到的packet
 * @param dst_fd	h264码流文件的句柄
 * 
 * @return	成功则返回零
 */
int process_h264(const AVPacket *in, const FILE *dst_fd)

实现源码:

#include <stdio.h>
#include <libavutil/log.h>
#include <libavformat/avio.h>
#include <libavformat/avformat.h>

#ifndef AV_WB32
#define AV_WB32(p, val) do {                 \
        uint32_t d = (val);                     \
        ((uint8_t*)(p))[3] = (d);               \
        ((uint8_t*)(p))[2] = (d)>>8;            \
        ((uint8_t*)(p))[1] = (d)>>16;           \
        ((uint8_t*)(p))[0] = (d)>>24;           \
    } while(0)
#endif

static int alloc_and_copy(AVPacket *out,
                          const uint8_t *in, uint32_t in_size)
{
    uint32_t offset         = out->size;
    uint8_t nal_header_size = 4;
    int err;

    err = av_grow_packet(out, in_size + nal_header_size);
    if (err < 0)
        return err;

    memcpy(out->data + nal_header_size + offset, in, in_size);
	
    AV_WB32(out->data, 1);

    return 0;
}

int process_h264(const AVPacket *in, FILE *dst_fd)
{
    AVPacket *out = NULL;

    int len;
    uint8_t unit_type;
    int32_t nal_size;
    uint32_t cumul_size    = 0;
    const uint8_t *buf;
    const uint8_t *buf_end;
    int            buf_size;
    int ret = 0, i, count = 0;
	
	out = av_packet_alloc();

    buf      = in->data;
    buf_size = in->size;
    buf_end  = in->data + in->size;

    do {
        ret= AVERROR(EINVAL);
        if (buf + 4 > buf_end)
            goto fail;

        for (nal_size = 0, i = 0; i<4; i++)
            nal_size = (nal_size << 8) | buf[i];

        buf += 4;
        unit_type = *buf & 0x1f;

		printf("nalu_type = %d, nalu_size = %d, while count = %d\n", 
			unit_type, nal_size, count++);
        if (nal_size > buf_end - buf || nal_size < 0)
            goto fail;

        if ((ret=alloc_and_copy(out, buf, nal_size)) < 0)
            goto fail;

        len = fwrite( out->data, 1, out->size, dst_fd);
        if(len != out->size){
            av_log(NULL, AV_LOG_WARNING, "warning, length of writed data isn't equal pkt.size(%d, %d)\n",
                    len,
                    out->size);
        }
        fflush(dst_fd);
		av_packet_unref(out);

		// next_nal
        buf        += nal_size;
        cumul_size += nal_size + 4;
    } while (cumul_size < buf_size);

fail:
    av_packet_free(&out);

    return ret;
}

static const char *help="usage: extra_video	src_filename dst_filename\n";

int main(int argc, char *argv[])
{
    int ret_code;		// 函数返回值
    char errors[1024];	// 存储av_strerror(error code)得到的信息

    char *src_filename = NULL;
    char *dst_filename = NULL;

    FILE *dst_fd = NULL;

    int video_stream_index = -1;

    AVFormatContext *fmt_ctx = NULL;
    AVPacket pkt;

    av_log_set_level(AV_LOG_INFO);

    if(argc < 3){
        av_log(NULL, AV_LOG_INFO, "%s", help);
        return -1;
    }

    src_filename = argv[1];
    dst_filename = argv[2];

    if(src_filename == NULL || dst_filename == NULL){
        av_log(NULL, AV_LOG_ERROR, "src or dts file is null, check them!\n");
        return -1;
    }

    dst_fd = fopen(dst_filename, "wb");
    if (!dst_fd) {
        av_log(NULL, AV_LOG_ERROR, "Could not open destination file %s\n", dst_filename);
        return -1;
    }

	av_register_all();
    /*open input media file, and allocate format context*/
    if((ret_code = avformat_open_input(&fmt_ctx, src_filename, NULL, NULL)) < 0){
        av_strerror(ret_code, errors, 1024);
        av_log(NULL, AV_LOG_ERROR, "Could not open source file: %s, %d(%s)\n",
               src_filename,
               ret_code,
               errors);
        return -1;
    }

    /*dump input information*/
    av_dump_format(fmt_ctx, 0, src_filename, 0);

    /*initialize packet*/
    av_init_packet(&pkt);
    pkt.data = NULL;
    pkt.size = 0;

    /*find best video stream*/
    video_stream_index = av_find_best_stream(fmt_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0);
    if(video_stream_index < 0){
        av_log(NULL, AV_LOG_ERROR, "Could not find %s stream in input file %s\n",
               av_get_media_type_string(AVMEDIA_TYPE_VIDEO),
               src_filename);
        return AVERROR(EINVAL);
    }

    /*read frames from media file*/
    while(av_read_frame(fmt_ctx, &pkt) >=0 ){
        if(pkt.stream_index == video_stream_index){
            process_h264(&pkt, dst_fd);
        }

        av_packet_unref(&pkt);
    }

    /*close input media file*/
    avformat_close_input(&fmt_ctx);
    if(dst_fd) {
        fclose(dst_fd);
    }

    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
要在Linux环境中编写C语言代码,使用FFmpeg提取mp4文件中的h264文件,你需要安装FFmpeg库和相应的头文件。可以在终端中输入以下命令进行安装: ``` sudo apt-get update sudo apt-get install ffmpeg libavcodec-dev libavformat-dev libavutil-dev libswscale-dev ``` 安装完成后,你可以使用以下代码来提取mp4文件中的h264文件: ```c #include <stdio.h> #include <libavcodec/avcodec.h> #include <libavformat/avformat.h> #include <libavutil/avutil.h> int main(int argc, char *argv[]) { AVFormatContext *formatContext = NULL; AVCodecContext *codecContext = NULL; AVCodec *codec = NULL; AVPacket packet; int streamIndex = -1; av_register_all(); if (avformat_open_input(&formatContext, argv[1], NULL, NULL) != 0) { printf("Error: Cannot open input file\n"); return -1; } if (avformat_find_stream_info(formatContext, NULL) < 0) { printf("Error: Cannot find stream information\n"); return -1; } for (int i = 0; i < formatContext->nb_streams; i++) { if (formatContext->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { streamIndex = i; break; } } if (streamIndex == -1) { printf("Error: Cannot find video stream\n"); return -1; } codec = avcodec_find_decoder(formatContext->streams[streamIndex]->codecpar->codec_id); codecContext = avcodec_alloc_context3(codec); if (avcodec_parameters_to_context(codecContext, formatContext->streams[streamIndex]->codecpar) < 0) { printf("Error: Cannot copy codec parameters to decoder context\n"); return -1; } if (avcodec_open2(codecContext, codec, NULL) < 0) { printf("Error: Cannot open codec\n"); return -1; } FILE *file = fopen(argv[2], "wb"); int frameFinished = 0; while (av_read_frame(formatContext, &packet) >= 0) { if (packet.stream_index == streamIndex) { avcodec_send_packet(codecContext, &packet); while (avcodec_receive_frame(codecContext, frame) == 0) { fwrite(codecContext->frame->data[0], 1, codecContext->frame->linesize[0], file); frameFinished = 1; } av_packet_unref(&packet); } } fclose(file); avcodec_free_context(&codecContext); avformat_close_input(&formatContext); avformat_free_context(formatContext); return 0; } ``` 在终端中编译并运行该程序: ``` gcc extract_h264_from_mp4.c -o extract_h264_from_mp4 -lavcodec -lavformat -lavutil -lswscale ./extract_h264_from_mp4 input.mp4 output.h264 ``` 其中,input.mp4是要提取h264文件的mp4文件名,output.h264提取出来的h264文件名。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

安河桥

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值