ffmpeg C代码实现 把视频流转换成图片保存到本地

用C代码实现,把视频中的帧转换成图片保存在本地。

#include <stdio.h>
#include <stdlib.h>
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavutil/avutil.h>
#include "libavutil/log.h"
int main(){
    // char* filename = "./jichi.mp4";
    //如果本地没有视频可以使用这个直播流地址
    char* filename = "http://weblive.hebtv.com/live/hbws_bq/index.m3u8";
    AVFormatContext* avf_cxt = avformat_alloc_context();
    int ret = avformat_open_input(&avf_cxt,filename,NULL,NULL);
    if(ret < 0){
        av_log(NULL,AV_LOG_ERROR,"不能打开文件\n");
        return -1;
    }
    ret = avformat_find_stream_info(avf_cxt,NULL);
    if(ret < 0){
        av_log(NULL,AV_LOG_ERROR,"找不到流数据\n");
        goto _end;
    }
    //打印视频信息
    av_dump_format(avf_cxt,0,filename,0);
    int video_index = -1;
    for(int i = 0 ; i < avf_cxt->nb_streams; i++){
        if(avf_cxt->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO){
            video_index = i;
            break;
        }
    }
    if(video_index == -1){
        av_log(NULL,AV_LOG_ERROR,"没有找到视频流\n");
        goto _end;
    }
    AVCodecContext* avc_cxt = avf_cxt->streams[video_index]->codec;
    enum AVCodecID codecId = avc_cxt->codec_id;
    AVCodec* codec = avcodec_find_decoder(codecId);
    if(!codec){
        av_log(NULL,AV_LOG_ERROR,"没有找到解码器\n");
        goto _end;
    }
    ret = avcodec_open2(avc_cxt,codec,NULL);
    if(ret < 0){
        av_log(NULL,AV_LOG_ERROR,"解码器无法打开\n");
        goto _end;
    }
    //为avpacket分配内存
    AVPacket* packet = av_packet_alloc();
    //为avFrame分配内存
    AVFrame* frame = av_frame_alloc();
    while(av_read_frame(avf_cxt,packet) >= 0){
        if(packet && packet->stream_index == video_index){
            int gotFrame = 0;
            ret = avcodec_decode_video2(avc_cxt,frame,&gotFrame,packet);
            if(gotFrame){
                ret = writeJPEG(frame,avc_cxt->width,avc_cxt->height);
                if(ret == 0){
                    break;
                }
            }
        }
    }

    _end:
    av_frame_free(frame);
    avcodec_close(avc_cxt);
    avformat_free_context(avf_cxt);
    return 0;
}
int writeJPEG(AVFrame* frame,int width,int height){
    const char* out_file = "hello_world.jpg";
    //新建一个输出的AVFormatContext 并分配内存
    AVFormatContext* output_cxt = avformat_alloc_context();
    avformat_alloc_output_context2(&output_cxt,NULL,"singlejpeg",out_file);

    //设置输出文件的格式
    // output_cxt->oformat = av_guess_format("mjpeg",NULL,NULL);

    //创建和初始化一个和该URL相关的AVIOContext
    if(avio_open(&output_cxt->pb,out_file,AVIO_FLAG_READ_WRITE) < 0){
        av_log(NULL,AV_LOG_ERROR,"不能打开文件  \n");
        return -1;
    }

    //构建新的Stream
    AVStream* stream = avformat_new_stream(output_cxt,NULL);
    if(stream == NULL){
        av_log(NULL,AV_LOG_ERROR,"创建AVStream失败  \n");
        return -1;
    }
    //初始化AVStream信息
    AVCodecContext* codec_cxt = stream->codec;

    codec_cxt->codec_id = output_cxt->oformat->video_codec;
    codec_cxt->codec_type = AVMEDIA_TYPE_VIDEO;
    codec_cxt->pix_fmt = AV_PIX_FMT_YUVJ420P;
    codec_cxt->height = height;
    codec_cxt->width = width;
    codec_cxt->time_base.num = 1;
    codec_cxt->time_base.den = 25;

    //打印输出文件信息
    av_dump_format(output_cxt,0,out_file,1);

    AVCodec* codec = avcodec_find_encoder(codec_cxt->codec_id);
    if(!codec){
        av_log(NULL,AV_LOG_ERROR,"找不到编码器  \n");
        return -1;
    }

    if(avcodec_open2(codec_cxt,codec,NULL) < 0){
        av_log(NULL,AV_LOG_ERROR,"不能打开编码器  \n");
        return -1;
    }
    avcodec_parameters_from_context(stream->codecpar,codec_cxt);

    //写入文件头
    avformat_write_header(output_cxt,NULL);
    int size = codec_cxt->width * codec_cxt->height;

    AVPacket* packet;
    av_new_packet(packet,size * 3);

    int got_picture = 0;
    int result = avcodec_encode_video2(codec_cxt,packet,frame,&got_picture);
    if(result < 0){
        av_log(NULL,AV_LOG_ERROR,"编码失败  \n");
        return -1;
    }
    printf("got_picture %d \n",got_picture);
    if(got_picture == 1){
        //将packet中的数据写入本地文件
        result = av_write_frame(output_cxt,packet);
    }
    av_free_packet(packet);
    //将流尾写入输出媒体文件并释放文件数据
    av_write_trailer(output_cxt);
    if(frame){
        av_frame_unref(frame);
    }
    avio_close(output_cxt->pb);
    avformat_free_context(output_cxt);
    return 0;
}
  • 5
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
### 回答1: 可以使用以下代码来更改视频1的封面:ffmpeg -i 视频1.mp4 -i 图片1.jpg -map 0:v -map 1:v -c:v copy -c:a copy -disposition:0 attached_pic 视频1_new.mp4 ### 回答2: 使用FFmpeg可以很方便地将视频的封面替换为另一张图片。下面是一份详细的代码示例: 1. 首先,确保已经安装了FFmpeg,并将其加入系统路径。你可以从FFmpeg的官方网站(https://ffmpeg.org/)下载并安装它。 2. 创建一个文本文件,将以下代码粘贴到文件中,并保存为一个脚本文件(例如,replace_cover.sh): ```shell #!/bin/bash # 视频的路径和文件名 input_file="video1.mp4" # 图片的路径和文件名 cover_image="image1.jpg" ffmpeg -i $input_file -i $cover_image -map 0 -map 1 -c copy -disposition:v:0 attached_pic output.mp4 ``` 3. 将视频文件(video1.mp4)和待替换封面的图像文件(image1.jpg)放在与脚本文件相同的目录下。 4. 在终端中,使用以下命令运行脚本文件: ```shell ./replace_cover.sh ``` 在脚本运行后,将会生成一个名为output.mp4的新视频文件,其中视频1的封面将会被图片1替换。 需要注意的是,上述代码假设视频文件和封面图像文件都位于同一个目录下。如果它们位于不同的目录,需要在代码中指定完整的路径。 此外,还需确保视频文件和图像文件的格式是兼容的。通常,FFmpeg支持的格式非常广泛,但某些特殊格式可能会存在兼容性问题。如果遇到问题,可以尝试将视频和图像转换为受支持的格式。 ### 回答3: 使用FFmpeg视频1的封面换成图片1的详细代码如下: ```bash ffmpeg -i 视频1.mp4 -i 图片1.jpg -map 0 -map 1 -c copy -disposition:1 attached_pic -y 新视频.mp4 ``` 这段代码使用了FFmpeg命令行工具进行操作。具体解释如下: - `-i 视频1.mp4` :表示输入的视频文件为"视频1.mp4"。可以根据实际情况替换为自己的视频文件名。 - `-i 图片1.jpg` :表示输入的图片文件为"图片1.jpg"。可以根据实际情况替换为自己的图片文件名。 - `-map 0 -map 1` :表示将视频流和图像流分别映射到输出文件上。 - `-c copy` :表示对视频图片进行直接复制操作,不进行编码。 - `-disposition:1 attached_pic` :表示将图片设置为封面。 - `-y 新视频.mp4` :表示输出的新视频文件为"新视频.mp4"。可以根据实际情况替换为自己想要的输出文件名。 执行代码后,FFmpeg将会将视频1中的封面替换为图片1,并生成一个新的视频文件"新视频.mp4"。
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值