MJPEG 解码后,编码为H264,分辨率改成1920x1080,采集的视频一大半是绿色的

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <fcntl.h>

#include <unistd.h>

#include <sys/ioctl.h>

#include <sys/mman.h>

#include <linux/videodev2.h>

#include <libavcodec/avcodec.h>

#include <libavformat/avformat.h>

#include <libavutil/opt.h>

#include <libswscale/swscale.h>

#define  VideoWidth  640

#define  VideoHeight 480

void Decode_Mjpeg(AVCodecContext *decodec_ctx, AVPacket *packet, AVFrame *frame,  AVFrame *frame_en, FILE *outfile)

{

    int ret = 0;

    int i = 0;

    int j = 0;

    //向解码器输入数据

    ret = avcodec_send_packet(decodec_ctx, packet);

    if(ret < 0)

    {

        av_log(NULL, AV_LOG_INFO, "Failed to send a packet to decoder!\n");

        exit(1);

    }

    while(ret >= 0)

    {//解码器输出数据

        ret = avcodec_receive_frame(decodec_ctx, frame);

        //若数据不足以解码或者数据用完了

        if( ret == AVERROR(EAGAIN) || ret == AVERROR_EOF){

                    return;

                }else if (ret <0){

                    printf("Error, Failed to decode!\n");

                    exit(1);

                }


 

        if(outfile)

        {

            //将Frame中存储的 YUV422 转换为 YUV420

            // U / V存储格式一样

            // frame->data[1]举例    数据包宽高分别为VideoWidth/2 、VideoHeight/2

            //UUUUUUUUUUUUU         UUUUUUUUUUUUUU

            //UUUUUUUUUUUUU   -  >

            //UUUUUUUUUUUUU   -  >UUUUUUUUUUUUUU

            //UUUUUUUUUUUUU

            for(i = 0; i < VideoHeight/2; i ++)

            {

                for(j = 0; j < VideoWidth/2; j ++)

                {

                    frame->data[1][(VideoWidth/2) * i + j] = frame->data[1][(VideoWidth/2) * i * 2+ j];

                    frame->data[2][(VideoWidth/2) * i + j] = frame->data[2][(VideoWidth/2) * i * 2+ j];

                }

            }

            //YUV422->YUV420多余数据置0

            for(i = 0; i < 307200/4; i ++)

            {

                frame->data[1][307200/4 + i] = 0;

                frame->data[2][307200/4 + i] = 0;

            }

            //先后向文件输出Y U V 数据

            fwrite(frame->data[0], 1, 307200, outfile);

            fwrite(frame->data[1], 1, 307200/4, outfile);

            fwrite(frame->data[2], 1, 307200/4, outfile);

            fflush(outfile);

            //把数据拷贝到输入H264编码器的Frame中

            memcpy(frame_en->data[0], frame->data[0], 307200);

            memcpy(frame_en->data[1], frame->data[1], 307200/4);

            memcpy(frame_en->data[2], frame->data[2], 307200/4);

        }

            av_frame_unref(frame);

    }

}

/*

 * @brief 打开设备

 * @param: void

 *@return:  AVFormatContext* fmt_ctx 设备格式上下文

*/

AVFormatContext* OpenDevice(void)

{

    //打开视频设备相关定义

    AVFormatContext* fmt_ctx = NULL; //格式上下文

    char *deviceName = "/dev/video1"; //视频设备

    AVDictionary *options = NULL;

    int device_open_ret=0; //打开成功与否标识

    char errorbuf[1024] = {0};

    //set log level

    av_log_set_level(AV_LOG_DEBUG);

    //注册设备all

    avdevice_register_all();

    //设置采集输入方式Format

    const AVInputFormat* avformat = av_find_input_format("video4linux2");

    //视频设备添入 options参数 分辨率/帧率

    av_dict_set(&options, "video_size", "640x480", 0);

    av_dict_set(&options, "framerate", "30", 0);

 //  av_dict_set(&options, "pixel_format", "mjpeg", 0);

    av_dict_set(&options, "input_format", "mjpeg", 0);


 

    //avformat_open_input(输出地址,设备名, 输入方式, 解码端)

    if((device_open_ret = avformat_open_input(&fmt_ctx, deviceName, avformat, &options))< 0) //如果打开设备出错

    {

        //返回错误码

        av_strerror(device_open_ret, errorbuf,1024);

        //打印错误信息

        av_log(NULL, AV_LOG_INFO, "Failed to open device, [%d]%s\n", device_open_ret, errorbuf);

        return NULL;

    }

    return fmt_ctx;

}

/*

 * @brief 打开编码器

 * @param: int width, int height 分辨率的宽高

 *@return:  AVCodecContext* codec_ctx 编码器上下文

*/

AVCodecContext* OpenEncoder(int width, int height)

{

    const AVCodec *codec = NULL;

    AVCodecContext *codec_ctx = NULL;

    int ret = 0;

    //选择libx264编码器

    codec = avcodec_find_encoder_by_name("libx264");

    if(!codec)

    {

        av_log(NULL, AV_LOG_INFO, "ERROR, this codec not found!\n");

        exit(1);

    }

    //编码器上下文

    codec_ctx = avcodec_alloc_context3(codec);

    if(!codec_ctx)

    {

        av_log(NULL, AV_LOG_INFO, "Failed to create Codec Ctx!\n");

        exit(1);

    }

    //设置H264编码参数

    //SPS / PPS

    codec_ctx->profile = FF_PROFILE_H264_HIGH_444; //H264 Profile

    codec_ctx->level = 50; //H264 Level = 5.0

    //分辨率

    codec_ctx->width = width;   //640

    codec_ctx->height = height;//480

    //GOP

    codec_ctx->gop_size = 250; //设的大一点

    codec_ctx->keyint_min = 25; //最小值

    //B帧

    codec_ctx->max_b_frames = 3;//b帧数量

    codec_ctx->has_b_frames = 1;// 需要b帧

    //参考帧

    codec_ctx->refs = 3; //参考帧数量

    //设置输入的YUV格式

    codec_ctx->pix_fmt = AV_PIX_FMT_YUV420P; //libx264需要 YUV420 的输入

    //设置码率

    codec_ctx->bit_rate = 600000; // 分辨率 x 帧率 x 8位深 x 1.5(yuv420p)

    //设置帧率

    codec_ctx->time_base = (AVRational){1, 30};

    codec_ctx->framerate = (AVRational){30, 1};

    ret = avcodec_open2(codec_ctx, codec, NULL);

    if(ret < 0)

    {

        av_log(NULL, AV_LOG_INFO, "Failed to open the codec, %s\n!", av_err2str(ret));

        exit(1);

    }


 

    return codec_ctx;

}

/*

 * @brief 打开解码器

 * @param: int width, int height 分辨率的宽高

 *@return:  AVCodecContext* codec_ctx 编码器上下文

*/

AVCodecContext* OpenDecoder(int width, int height)

{

    const AVCodec *decodec = NULL;

    AVCodecContext *decodec_ctx = NULL;

    int ret = 0;

    //选择编码器

    decodec = avcodec_find_decoder(AV_CODEC_ID_MJPEG);

    if(!decodec)

    {

        av_log(NULL, AV_LOG_INFO, "Failed to create MJPEG Decoder!\n");

        exit(1);

    }

    //编码器上下文初始化

    decodec_ctx = avcodec_alloc_context3(decodec);

    if(!decodec_ctx)

    {

        av_log(NULL, AV_LOG_INFO, "Failed to create MJPEG Decoder Ctx!\n");

        exit(1);

    }

    //分辨率

    decodec_ctx->width = width;   //640

    decodec_ctx->height = height;//480

    ret = avcodec_open2(decodec_ctx, decodec, NULL);

    if(ret < 0)

    {

        av_log(NULL, AV_LOG_INFO, "Failed to open the codec, %s\n!", av_err2str(ret));

        exit(1);

    }


 

    return decodec_ctx;

}


 

/*

 * @brief 创建编码器输入数据包Frame'

 * @param: Frame的参数:int width, int height 分辨率的宽高; 数据pix_fmt格式 enum AVPixelFormat pixfmt

 *@return:  AVFrame* frame 编码器输入数据包

*/

AVFrame* CreateFrame(int width, int height, enum AVPixelFormat pixfmt)

{

    AVFrame *frame = NULL;

    int ret = 0;

    //frame初始化

    frame = av_frame_alloc();

    if(!frame)

    {

        av_log(NULL, AV_LOG_INFO, "Failed to create frame!\n");

        goto __ERROR;

    }

    //设置编码器输入数据包参数

    frame->width = width;

    frame->height = height;

    frame->format = pixfmt;

    //frame获取数据空间

    ret = av_frame_get_buffer(frame, 32);

    if(ret < 0)

    {

        av_log(NULL, AV_LOG_INFO, "Failed to get Frame Buffer!\n");

        goto __ERROR;

    }

    return frame;

__ERROR:

    if(frame)

        av_frame_free(&frame);

    return NULL;

}


 

/*

 * @brief 编码器H264

 * @param: AVCodecContext *decodec_ctx, 编码器上下文

 *                AVPacket *packet,    编码器输入数据包packet

 *                AVFrame *frame,      编码器输出数据包frame

 *                FILE *outfile             文件名 若不用可设为NULL

 *@return:  NULL

*/

void Encode_H264(AVCodecContext *codec_ctx, AVFrame *frame, AVPacket *packet, FILE *outfile)

{

    int ret = 0;

    //打印PTS

    if(frame)

    {

        av_log(NULL, AV_LOG_INFO, "send frame to encoder, pts=%ld\n", frame->pts);

    }

    //向编码器送数据

    ret = avcodec_send_frame(codec_ctx, frame);

    if(ret < 0)

    {

        av_log(NULL, AV_LOG_INFO, "Failed to send Frame to encodec,ret = %d!\n", ret);

        exit(1);

    }


 

    while(ret >= 0)

    {

        //接收编码完成的数据

        ret = avcodec_receive_packet(codec_ctx, packet);

        //如果数据不足或者数据用完了

        if(ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)

                return;

        else if (ret < 0) {

            av_log(NULL, AV_LOG_INFO, "Failed to encodec!\n");

            exit(1);

        }

        if(outfile)

        {

            fwrite(packet->data, 1, packet->size, outfile);

            av_packet_unref(packet);

        }

    }

}

int main()

{

    //set log level

    av_log_set_level(AV_LOG_DEBUG);

    //上下文

    AVFormatContext *fmt_ctx = NULL;

    AVCodecContext *codec_ctx = NULL;

    AVCodecContext *decodec_ctx = NULL;

   

    AVFrame *frame_decodec= NULL;

    AVFrame *frame_encodec= NULL;

    AVPacket *packet_de= NULL;

    AVPacket *packet_en= NULL;

    AVPacket  pkt;

    int count = 0;

    int base = 0;

   char *outfileName = "/home/pi/mjpeg/11.yuv";

   FILE *outFile = fopen(outfileName, "wb+");

   char *h264fileName = "/home/pi/mjpeg/1.h264";

   FILE *h264File = fopen(h264fileName, "wb+");

   if(!outFile)

   {

       av_log(NULL, AV_LOG_INFO, "Failed to create outFile!");

       goto __ERROR;

   }

   fmt_ctx = OpenDevice();

   decodec_ctx = OpenDecoder(VideoWidth, VideoHeight);

   codec_ctx = OpenEncoder(VideoWidth, VideoHeight);

   frame_decodec = CreateFrame(VideoWidth, VideoHeight, AV_PIX_FMT_YUV420P);

   frame_encodec = CreateFrame(VideoWidth, VideoHeight, AV_PIX_FMT_YUV420P);

   packet_de= av_packet_alloc();

   packet_en= av_packet_alloc();

   if(!packet_de || !packet_en)

   {

       av_log(NULL, AV_LOG_INFO, "Failed to create Packet!\n");

       goto __ERROR;

   }

   if( av_new_packet(packet_de, 150000)< 0)

   {

       av_log(NULL, AV_LOG_INFO, "Failed to get Packet Buffer!\n");

       goto __ERROR;

   }

   while((av_read_frame(fmt_ctx, &pkt)  == 0))

   {

       av_log(NULL, AV_LOG_INFO, "Pac size = %d(%p), Count = %d \n",

                                                                   pkt.size,

                                                                   pkt.data,

                                                                   count       );

       memcpy(packet_de->data, pkt.data, pkt.size);

       Decode_Mjpeg(decodec_ctx, packet_de, frame_decodec, frame_encodec, outFile);

       frame_encodec->pts = base++;

       Encode_H264(codec_ctx, frame_encodec, packet_en, h264File);

       count ++;

       av_packet_unref(&pkt); //释放pkt

   }

   //将剩余数据进行处理

   Decode_Mjpeg(decodec_ctx, NULL, frame_decodec, NULL, outFile);

   Encode_H264(codec_ctx, NULL, packet_en, h264File);

   av_log(NULL, AV_LOG_INFO, "Finished");

__ERROR:

   //关闭文件

   if(outFile)

       fclose(outFile);

   //释放

   if(fmt_ctx)

       avformat_close_input(&fmt_ctx);

   if(codec_ctx)

       avcodec_close(codec_ctx);

   if(frame_decodec)

       av_frame_free(&frame_decodec);

   if(frame_encodec)

       av_frame_free(&frame_encodec);

   if(packet_de)

       av_packet_free(&packet_de);

   if(packet_en)

       av_packet_free(&packet_en);

   return;

}

  • 5
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值