【无标题】

#include "capencpush.h"
#include "media.h"



#define VideoWidth      640//640
#define VideoHeight     480//480


void Cap_Eec_Push(void)
{
    //set log level
    av_log_set_level(AV_LOG_DEBUG);

    //设备上下文
    AVFormatContext *fmt_ctx = NULL;
    AVFormatContext *out_ctx = NULL;
    AVCodecContext *encodec_ctx = NULL;
    AVCodecContext *decodec_ctx = NULL;
    AVFrame *frame_decodec= NULL;
    AVFrame *frame_encodec= NULL;
    AVPacket *packet_de= NULL;
    AVPacket *packet_en= NULL;
    AVPacket *pushpacket = NULL;
    AVPacket  pkt;
    AVStream *out_stream = NULL;
    AVStream *out1_stream = NULL;
    AVRational intime_base;
    AVRational inframe_rate;

    int video_index = -1;
    int count = 0;
    int base = 0;
    int videosize = 0;
    int64_t start_time = 0;

    //写入数据文件相关定义
   char *pushstreamaddr = "rtmp://192.168.0.110:1935/live/stream";
   char *outfileName = "/home/smallred/video_work/mediawork/11.yuv";
   FILE *outFile = fopen(outfileName, "wb+"); //写 二进制 创建
   char *h264fileName = "/home/smallred/video_work/mediawork/3.h264";
   FILE *h264File = fopen(h264fileName, "wb+"); //写 二进制 创建
   if(!outFile)
   {
       av_log(NULL, AV_LOG_INFO, "Failed to create outFile!");
       goto __ERROR;
   }

   //
   //打开设备 获取设备格式上下文
   fmt_ctx = cep_OpenDevice();
   cep_GetInputStream(&fmt_ctx, &video_index, &intime_base, &inframe_rate);

   //打开解码器
   decodec_ctx = cep_OpenDecoder(VideoWidth, VideoHeight);
   //打开编码器
   encodec_ctx = cep_OpenEncoder(VideoWidth, VideoHeight);


   out_ctx = cep_OutStream_Alloc(pushstreamaddr, encodec_ctx, &out_stream);

   //创建Frame
   frame_decodec = cep_CreateFrame(VideoWidth, VideoHeight, AV_PIX_FMT_YUV422P);
   frame_encodec = cep_CreateFrame(VideoWidth, VideoHeight, AV_PIX_FMT_YUV420P);
   //创建Packet
   packet_de= av_packet_alloc();
   packet_en= av_packet_alloc();
   pushpacket = av_packet_alloc();
   if(!packet_de || !packet_en)
   {
       av_log(NULL, AV_LOG_INFO, "Failed to create Packet!\n");
       goto __ERROR;
   }
   //packet获取数据空间
   if( av_new_packet(packet_de, 150000)< 0)
   {
       av_log(NULL, AV_LOG_INFO, "Failed to get Packet Buffer!\n");
       goto __ERROR;
   }
   //计算输出视频码流的分辨率
   videosize = out_stream->codecpar->width * out_stream->codecpar->height;
   av_log(NULL, AV_LOG_INFO, "videosize = %d!\n", videosize);
   if( av_new_packet(packet_en, videosize)< 0)
   {
       av_log(NULL, AV_LOG_INFO, "Failed to get Packet Buffer_en!\n");
       goto __ERROR;
   }


   out1_stream = out_ctx->streams[video_index];

   start_time = av_gettime();
   //读数据
   while((av_read_frame(fmt_ctx, &pkt)  == DeviceRead_Suc)
           && (audioStartorStop == true))
   {
       av_log(NULL, AV_LOG_INFO, "Pac size = %d(%p), Count = %d \n",
                                                                   pkt.size,
                                                                   pkt.data,
                                                                   count       );

       //将数据拷贝到Packet 中 等待送入MJPEG解码器
       memcpy(packet_de->data, pkt.data, pkt.size);
       //MJPEG解码
       cep_Decode(decodec_ctx, packet_de, frame_decodec, frame_encodec, outFile);

       frame_encodec->pts = base++;
       cep_Encode(encodec_ctx, frame_encodec, &packet_en, h264File);

       //memcpy(pushpacket->data, packet_en->data, packet_en->size);
       //推流
       cep_TransAndPush(encodec_ctx, out_ctx, fmt_ctx, packet_en, start_time, out_stream);

       count ++;
       av_packet_unref(packet_en);
       av_packet_unref(&pkt); //释放pkt
   }
   //将剩余数据进行处理
   cep_Decode(decodec_ctx, NULL, frame_decodec, frame_encodec, outFile);
   cep_Encode(encodec_ctx, frame_encodec, &packet_en, h264File);
   cep_Encode(encodec_ctx, NULL, &packet_en,h264File);

   //memcpy(pushpacket->data, packet_en->data, packet_en->size);
   cep_TransAndPush(encodec_ctx, out_ctx, fmt_ctx, packet_en, start_time, out_stream);
   //写文件尾(Write file trailer)
   av_write_trailer(out_ctx);
   avio_close(out_ctx->pb);
   av_log(NULL, AV_LOG_INFO, "Finished");

__ERROR:
   //关闭文件
   if(outFile)
       fclose(outFile);
   if(h264File)
       fclose(h264File);
   //释放
   if(fmt_ctx)
   {
       avformat_close_input(&fmt_ctx);
       avformat_free_context(fmt_ctx);
   }
   if(out_ctx)
   {
       avformat_close_input(&out_ctx);
       avformat_free_context(out_ctx);
   }
   if(encodec_ctx)
       avcodec_close(encodec_ctx);
   if(decodec_ctx)
       avcodec_close(decodec_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);
   if(pushpacket)
       av_packet_free(&pushpacket);
   return;

}

/*
 * @brief 打开设备
 * @param: void
 *@return:  AVFormatContext* fmt_ctx 设备格式上下文
*/
AVFormatContext* cep_OpenDevice(void)
{
    //打开视频设备相关定义

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

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

    AVDictionary *options = NULL;

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

    char errorbuf[errorbuf_size] = {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", "10", 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))
                    < DeviceOpen_Suc) //如果打开设备出错
    {
        //返回错误码
        av_strerror(device_open_ret, errorbuf, errorbuf_size);
        //打印错误信息
        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* cep_OpenEncoder(int width, int height)
{
    const AVCodec *codec = NULL;
    AVCodecContext *codec_ctx = NULL;
    AVDictionary *options = NULL;
    int ret = 0;

    //选择libx265编码器
    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编码参数

    // 不设置时,仅第一个I帧前存一次sps和pps
    // 设置后,I帧前不会存储sps和pps
    // 但是,codec_ctx->extradata会有数据,需要手动处理
    //codec_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;

    codec_ctx->thread_count = 8;

    //SPS / PPS
    //codec_ctx->profile = FF_PROFILE_HEVC_MAIN;
    codec_ctx->profile = FF_PROFILE_H264_HIGH_444_INTRA;
    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 = 0;//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, 10};
    codec_ctx->framerate = (AVRational){10, 1};

    av_dict_set(&options, "preset", "ultrafast", 0);
    av_dict_set(&options, "tune", "zerolatency", 0);
//    av_opt_set(&options, "crf", "24", 0);
//    av_dict_set(&options, "rtsp_transport", "tcp", 0);

    ret = avcodec_open2(codec_ctx, codec, &options);
    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* cep_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  Decoder!\n");
        exit(1);
    }
    //编码器上下文初始化
    decodec_ctx = avcodec_alloc_context3(decodec);
    if(!decodec_ctx)
    {
        av_log(NULL, AV_LOG_INFO, "Failed to create  Decoder Ctx!\n");
        exit(1);
    }

    //分辨率
    decodec_ctx->width = width;   //640
    decodec_ctx->height = height;//480

    //设置码率
//     decodec_ctx->bit_rate = inctx->streams[video_index]->codecpar->bit_rate;

    //设置帧率
    decodec_ctx->time_base = (AVRational){1, 10};
    decodec_ctx->framerate = (AVRational){10, 1};

    //输出YUV格式
//    decodec_ctx->sw_pix_fmt = AV_PIX_FMT_YUV420P;
//    decodec_ctx->pix_fmt = inctx->streams[video_index]->codecpar->format;

//    decodec_ctx->profile = inctx->streams[video_index]->codecpar->profile;

    //打开解码器
    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* cep_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 解码器 MJPG
 * @param: AVCodecContext *decodec_ctx, 解码器上下文
 *                AVPacket *packet,    解码器输入数据包packet
 *                AVFrame *frame,      解码器输出数据包frame
 *                FILE *outfile             文件名 若不用可设为NULL
 *@return:  NULL
*/

void cep_Decode(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 编码器H265
 * @param: AVCodecContext *decodec_ctx, 编码器上下文
 *                AVPacket *packet,    编码器输入数据包packet
 *                AVFrame *frame,      编码器输出数据包frame
 *                FILE *outfile             文件名 若不用可设为NULL
 *@return:  NULL
*/

void cep_Encode(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);

    }


    return;
}

/*
 * @brief 读取频流信息 创建上下文 判断文件是否为视频流
 * @param[in]:  h264filename 正在操作的输入文件
 *@return:  AVFormatContext Failure: NULL
 */
 void cep_GetInputStream(AVFormatContext **inctx, int *video_index, AVRational *intime_base, AVRational *inframe_rate)
{
    int res;
    unsigned int i = 0;

    //获取输入文件流信息
    res = avformat_find_stream_info((*inctx), NULL);
    if(res < 0)
    {
        av_log(NULL, AV_LOG_INFO, "Failed to get input stream information!\n");
        goto __ERROR;
    }

    //遍历寻找视频流
    for(i = 0; i < (*inctx)->nb_streams; i ++)
    {
        //如果找到了视频流
        if((*inctx)->streams[i]->codecpar->codec_type== AVMEDIA_TYPE_VIDEO)
        {
            *video_index = i;
            *intime_base = (*inctx)->streams[i]->time_base;
            *inframe_rate = (*inctx)->streams[i]->r_frame_rate;
        }
        else
            break;
    }
    //找不到视频流
    if(*video_index < 0)
    {
        av_log(NULL, AV_LOG_INFO, "Failed to find video stream!\n");
        goto __ERROR;
    }

    av_log(NULL, AV_LOG_INFO, "video_index = %d!\n", *video_index);

    return;

__ERROR:

    if((*inctx))
    {
        avformat_close_input(inctx);
        av_free(inctx);
    }
    return;
}

/*
 * @brief 设置输出文件流格式 新建输出流
 * @param[in]:  newcodingfile 输出文件名, inctx 输入流格式上下文
 *@return:  AVFormatContext 输出流格式上下文; Failure: NULL
 */
AVFormatContext* cep_OutStream_Alloc(char* pushstreamaddr, AVCodecContext *encodec_ctx, AVStream **outstream)
{
    AVFormatContext *outctx = NULL;
    AVDictionary *opts = NULL;
    //const AVOutputFormat* outfmt = NULL;
    int res;

    avformat_network_init();

    outctx =avformat_alloc_context();
    //初始化
    avformat_alloc_output_context2(&outctx, NULL, "flv", pushstreamaddr);
    if(!outctx)
    {
        av_log(NULL, AV_LOG_INFO, "Failed to get out outctx!\n");
        goto __ERROR;
    }

    outctx->video_codec = encodec_ctx->codec;
    outctx->video_codec_id = encodec_ctx->codec_id;
    //新建视频流 AVCODEC =NULL
    (*outstream) = avformat_new_stream(outctx, NULL);
    if(!(*outstream))
    {
        av_log(NULL, AV_LOG_INFO, "Failed to create new stream!\n");
        goto __ERROR;
    }

    //复制参数
    res = avcodec_parameters_from_context((*outstream)->codecpar, encodec_ctx);
    //res = avcodec_parameters_to_context(encodec_ctx, (*outstream)->codecpar);

    (*outstream)->codecpar->codec_tag = 0;
    (*outstream)->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
    (*outstream)->codecpar->extradata_size = encodec_ctx->extradata_size;
    (*outstream)->codecpar->extradata = encodec_ctx->extradata;

    if(res < 0)
    {
        av_log(NULL, AV_LOG_INFO, "Failed to set stream codec param!\n");
        goto __ERROR;
    }




    //打开网络输出流: AVIOCtx* pb 输出文件, 打开方式
    res = avio_open(&outctx->pb, pushstreamaddr, AVIO_FLAG_WRITE);
    if(res < 0)
    {
        av_log(NULL, AV_LOG_INFO, "Failed to open new stream!\n");
        avio_close(outctx->pb);
        goto __ERROR;
    }

    //Dump Format
    av_dump_format(outctx, 0, pushstreamaddr, 1);

    av_dict_set(&opts, "flvflags", "add_keyframe_index", 0);

    //写入封装头信息
    res = avformat_write_header(outctx, NULL);
    if(res < 0)
    {
        av_log(NULL, AV_LOG_INFO, "Failed to write header, res = %d!\n", res);
        goto __ERROR;
    }
    av_dict_free(&opts);

    return outctx;

__ERROR:
    if(outctx)
    {
        avformat_close_input(&outctx);
        avformat_free_context(outctx);
    }
    //if(newstream)

    return NULL;
}


/*
 * @brief  转码
 * @param[in]:  inctx 输入上下文, outctx输出上下文, incodec_index输入视频码流下标, newstream新建码流对象
 *@return:  void
 */
void cep_TransAndPush(AVCodecContext *encodec_ctx, AVFormatContext *outctx, AVFormatContext *inctx, AVPacket *packet, int64_t start_time, AVStream *out_stream)
{
    static int frame_count = 0;
    AVRational time_base;
    AVRational time_base_q;
    AVRational time_base_new;
    int64_t duration;
    int64_t pts_time;
    int64_t now_time;
    int ret = 0;
    int num;
    int den;
    AVStream *new_stream;


    //查看是否有设置时间基 没有则
    if(packet->pts == AV_NOPTS_VALUE)
    {
        //时间基的转换
        num = encodec_ctx->time_base.num;
        den = encodec_ctx->time_base.den;
        time_base_new = encodec_ctx->time_base;
        //计算两帧码流数据之间的长度
        duration = (double)AV_TIME_BASE/av_q2d(encodec_ctx->framerate);
        //计算显示时间戳
        packet->pts = (double)(frame_count * duration)/(av_q2d(time_base_new) * AV_TIME_BASE);
        packet->dts = packet->pts;
        packet->duration = duration/(double)(av_q2d(time_base_new) * AV_TIME_BASE);
    }

//    else if(packet->pts < packet->dts)
//    {
//        av_packet_unref(packet);
//        return;
//    }
    //发送流媒体的数据的时候需要延时。不然的话,FFmpeg处理数据速度很快,
    // 瞬间就能把所有的数据发送出去,流媒体服务器是接受不了的。
    //因此需要按照视频实际的帧率发送数据。本文记录的推流器在视频帧与帧之间采用了av_usleep()函数休眠的方式来延迟发送。
    //这样就可以按照视频的帧率发送数据.
    time_base = encodec_ctx->time_base;
    time_base_q = (AVRational){1, AV_TIME_BASE};
    pts_time = av_rescale_q(packet->dts, time_base, time_base_q);
    now_time = av_gettime() - start_time;
    if(pts_time > now_time)
        av_usleep(pts_time - now_time);

    //in_stream = inctx->streams[packet->stream_index];
    //out_stream = outctx->streams[packet->stream_index];

//    packet->pts = av_rescale_q_rnd(packet->pts, encodec_ctx->time_base,
//                                                out_stream->time_base, (enum AVRounding)(AV_ROUND_INF | AV_ROUND_PASS_MINMAX));
//    packet->dts = av_rescale_q_rnd(packet->dts, encodec_ctx->time_base,
//                                                out_stream->time_base, (enum AVRounding)(AV_ROUND_INF | AV_ROUND_PASS_MINMAX));
//    packet->dts = packet->pts;

    new_stream = outctx->streams[packet->stream_index];

    packet->pts = av_rescale_q(packet->pts, encodec_ctx->time_base, new_stream->time_base);
    //packet->dts = av_rescale_q(packet->dts, encodec_ctx->time_base, out_stream->time_base);
    packet->dts = packet->pts;
    packet->duration = av_rescale_q(packet->duration, encodec_ctx->time_base, new_stream->time_base);
    //packet->pts = packet->dts = frame_count * (outctx->streams[0]->time_base.den) /outctx->streams[0]->time_base.num / 10;

    //准备写入
    packet->pos = -1;
//    packet->flags = AV_PKT_FLAG_KEY | packet->flags;
//    packet->stream_index = 0;
    //写入 Write a packet to an output media file ensuring correct erleaving.
    ret = av_interleaved_write_frame(outctx, packet);
    if (ret < 0)
    {
        av_log(NULL, AV_LOG_INFO,  "Error muxing packet:%d\n", ret);

    }
    else
        av_log(NULL, AV_LOG_INFO,  "Push Stream ing:%d..................\n", ret);

    frame_count ++;

    return;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值