FFMPEG 解码和编码(编码mjpeg)

以前的一个android工程, 把普通视频解码成yuv同时编成mjpeg, 把音频解码成pcm并调整参数。

初始化编码器和解码器


    av_register_all();
    if(avformat_open_input(&pFormatCtx, filename, NULL, NULL) != 0 )
    {
        LOGE("ERROR:avformat_open_input file: %s", filename);
        return -1; 
    }
    m2mjpeg_adpcm->pFormatCtx = pFormatCtx;
    if(avformat_find_stream_info(m2mjpeg_adpcm->pFormatCtx, NULL)<0){
        LOGE(" Couldn't find stream information");
        return -1; 
    }

// av_dump_format(m2mjpeg_adpcm->pFormatCtx, 0, filename, 0);

    videoStream = -1;
    audioStream = -1;
    int found = 0;
    for(i=0; i<pFormatCtx->nb_streams; i++)
    {
        if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_VIDEO) {
            videoStream=i;
            pStream[MJA_VIDEO] = pFormatCtx->streams[i];
        }else if (pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_AUDIO){
            audioStream = i;
        }
    }
    if(videoStream==-1){
        LOGE("Didn't find a video stream");
        return -1; 
    }

    if(audioStream==-1){
        LOGE("Didn't find a audio stream");
        return -1; 
    }
    m2mjpeg_adpcm->vdid = videoStream;
    m2mjpeg_adpcm->auid = audioStream;

配置编码器

    pCodecCtx[MJA_VIDEO]=pFormatCtx->streams[videoStream]->codec;
    // Find the decoder for the video stream
    pCodec[MJA_VIDEO]=avcodec_find_decoder(
            pCodecCtx[MJA_VIDEO]->codec_id);
    if(pCodec[MJA_VIDEO]==NULL) {
        LOGE("Unsupported codec!\n");
        return -1; // Codec not found
    }
// Open VIdeo codec
    if(avcodec_open2(pCodecCtx[MJA_VIDEO], 
                pCodec[MJA_VIDEO], &optionsDict)<0){
        LOGE("Could not open codec");
        return -1; 
    }
    m2mjpeg_adpcm->pCodecCtx[MJA_VIDEO] = pCodecCtx[MJA_VIDEO];
    // Allocate video frame
    m2mjpeg_adpcm->pDecodeFrame = av_frame_alloc();
    if (m2mjpeg_adpcm->pDecodeFrame == NULL){
        LOGE("Error Allocate an AVFrame structure");
        return -1;

    }
//初始化缩放结构
    m2mjpeg_adpcm->pSwsFrame = av_frame_alloc();
    if(m2mjpeg_adpcm->pSwsFrame == NULL){
        LOGE("Error Allocate an AVFrame structure");
        return -1;
    }
    LOGI("AVFrame Format pit %dx%d", width, height);
//设置分辨率
    m2mjpeg_adpcm->width = width;
    m2mjpeg_adpcm->height = height;

    // Determine required buffer size and allocate buffer
    int numBytes=avpicture_get_size(AV_PIX_FMT_YUV420P, 
            pCodecCtx[MJA_VIDEO]->width,
            pCodecCtx[MJA_VIDEO]->height);
    uint8_t *buffer=(uint8_t *)av_malloc(numBytes*sizeof(uint8_t));
//分辨率调整
    m2mjpeg_adpcm->sws_ctx =
        sws_getContext
        (
         pCodecCtx[MJA_VIDEO]->width,
         pCodecCtx[MJA_VIDEO]->height,
         pCodecCtx[MJA_VIDEO]->pix_fmt,
         width,
         height,
         AV_PIX_FMT_YUVJ420P,
         SWS_BILINEAR,
         NULL,
         NULL,
         NULL
        );
    // Assign appropriate parts of buffer to image planes in AVPicture
    avpicture_fill((AVPicture *)m2mjpeg_adpcm->pSwsFrame, 
            buffer, AV_PIX_FMT_YUVJ420P,
            width, height);

//音频解码器
    pStream[MJA_AUDIO] = pFormatCtx->streams[audioStream];
    m2mjpeg_adpcm->pCodecCtx[MJA_AUDIO] = pCodecCtx[MJA_AUDIO] = pStream[MJA_AUDIO]->codec;
    pCodec[MJA_AUDIO] = avcodec_find_decoder(
            m2mjpeg_adpcm->pCodecCtx[MJA_AUDIO]->codec_id) ;
    if(pCodec[MJA_AUDIO] != NULL){
        if(avcodec_open2(m2mjpeg_adpcm->pCodecCtx[MJA_AUDIO], 
                    pCodec[MJA_AUDIO], NULL)<0){
            LOGE("Could not open codec");
            return -1; 
        }
    }else{
        LOGE("NO AUDIO DATA");
        return -1; 
    }

//获取MJPEG编码器
    AVCodec *codec = avcodec_find_encoder(AV_CODEC_ID_MJPEG);
    if (codec == NULL){
        LOGE("ERROR:EnCoder Codec not found");
        return -1;
    }
    m2mjpeg_adpcm->pEnCodec = codec;
//申请Context 
    AVCodecContext *ctx = avcodec_alloc_context3(m2mjpeg_adpcm->pEnCodec);
    if (!ctx){
        LOGE("ERROR: alloc encode context failed");
        return -1;
    }
    ctx->bit_rate = bitrate;
    ctx->width = width;
    ctx->height = height;
    ctx->time_base = (AVRational ){1, 16};
    ctx->pix_fmt = AV_PIX_FMT_YUVJ420P;

    m2mjpeg_adpcm->pSwsFrame->format = ctx->pix_fmt;
    m2mjpeg_adpcm->pSwsFrame->width = width;
    m2mjpeg_adpcm->pSwsFrame->height = height;
//打开编码器 
    if (avcodec_open2(ctx, m2mjpeg_adpcm->pEnCodec, NULL) < 0) {
        LOGE("ERROR: Could not open codec");
        return -1;
    }
    m2mjpeg_adpcm->pEnCodecCtx = ctx;
    
    int ret = av_image_alloc(m2mjpeg_adpcm->pSwsFrame->data, 
            m2mjpeg_adpcm->pSwsFrame->linesize, 
            ctx->width, ctx->height,ctx->pix_fmt, 32);
    if (ret < 0){
        LOGE("ERROR:Could not Alloc Image");
       return -1;   
    }
//设置音频参数
    m2mjpeg_adpcm->samplerate = 32000;
    m2mjpeg_adpcm->sample_fmt = AV_SAMPLE_FMT_S16;
    m2mjpeg_adpcm->ch_layout = AV_CH_LAYOUT_STEREO;

    struct SwrContext *swr_ctx = swr_alloc();
    if (!swr_ctx){
        LOGE("ERROR:Cound alloc audio swr\n");
        return -1;
    }
       av_opt_set_int(swr_ctx, "in_sample_rate", c->sample_rate, 0);
       av_opt_set_sample_fmt(swr_ctx, "in_sample_fmt",c->sample_fmt, 0);
       av_opt_set_int(swr_ctx, "out_channel_layout", layout, 0);
       av_opt_set_int(swr_ctx, "out_sample_rate", sample_rate, 0);
       av_opt_set_sample_fmt(swr_ctx, "out_sample_fmt", sample_fmt, 0);
       av_opt_set_int(swr_ctx, "in_channel_layout",
            av_get_default_channel_layout(c->channels), 0);

    if (swr_init(swr_ctx) < 0){
        LOGE("ERROR:Count not init audio swr\n");
        swr_free(swr_ctx);
        return -1;
    }
    *swr = swr_ctx;

      *nb_samples = av_rescale_rnd(c->frame_size, sample_rate, c->sample_rate, AV_ROUND_UP);
      *nb_channels = av_get_channel_layout_nb_channels(layout);
      LOGI("nb_samples:%d, nb_channels:%d", *nb_samples, *nb_channels);



   if(av_samples_alloc_array_and_samples(&m2mjpeg_adpcm->abuf, &m2mjpeg_adpcm->linesize,
               m2mjpeg_adpcm->nb_channels,m2mjpeg_adpcm->nb_samples,
               m2mjpeg_adpcm->sample_fmt, 0) < 0 ){
       LOGE("Could not allocate destination samples\n");
       return -1;
   }
    LOGI("dst_linesize:%d, dst_nb_channels:%d, dst_nb_samples:%d\n", 
            m2mjpeg_adpcm->linesize, m2mjpeg_adpcm->nb_channels, m2mjpeg_adpcm->nb_samples);

编码与解码

  • 调整帧率,修改android nkd下帧率设置无效,自定义计算方式,比较粗略。
    double vfs = pMja->fps*pMja->duration/1000000;
    double vfi = 1000000/pMja->fps;
    double oldts = 1000000/pMja->src_fps;
    double newts = vfi;
    uint32_t oldcount = 0;
    uint32_t newcount = 0;
  • 设置自定义文件头
    mja_file_header_t file_header = {
        .audio_sample_rate = pMja->samplerate,
        .video_frames = (uint32_t)vfs,
        .video_frame_interval = (uint32_t)vfi,
        .crc_32 = 0,

    };
    file_header.crc_32 = crc32(&file_header, sizeof(file_header)-sizeof(uint32_t));
#if MJA_DEBUG
    //dump_file_header(&file_header);
#endif


    queue_push_data(queue, &file_header, sizeof(file_header));  
    pthread_mutex_lock(&pMja->mutex);
    pMja->ctl = MJA_START;
    pthread_mutex_unlock(&pMja->mutex);
  • 视频解码
      if(packet.stream_index==videoStream) {
        // Decode video frame
        avcodec_decode_video2(pCodecCtx[MJA_VIDEO], 
                pFDec, &frameFinished, &packet);
        // Save the frame to disk
        if (frameFinished)
        {
            double pts = av_frame_get_best_effort_timestamp(pFDec);
            pts = av_rescale_q ( pts,  *(pMja->time_base), AV_TIME_BASE_Q );
            int percent = (int)(pts/pMja->duration *100);

        //LOGI("pts: %f/%" PRId64 " = %d ", pts, pMja->duration , percent);
        }
  • 视频编码
    sws_scale(sws_ctx, 
            (uint8_t const * const *)pFDec->data,
            pFDec->linesize,
            0,
            pCodecCtx[MJA_VIDEO]->height, 
            pFSws->data, 
            pFSws->linesize);
    ret = avcodec_encode_video2(pMja->pEnCodecCtx, &pkt,
            pFSws, &got_encode_frame);
  • 音频解码
    ret = avcodec_decode_audio4(pCodecCtx[MJA_AUDIO], 
            pFDec, &frameFinished, &packet);
    if (ret < 0){
        LOGE("ERROR:Decoding Audio Frame (%s)\n", av_err2str(ret));
        break;
    }
  • 音频转换
    if (frameFinished){

        ret = swr_convert(pMja->audio_swr_ctx, abuf, pMja->nb_samples,
                (const uint8_t **)pFDec->data, pFDec->nb_samples);
        if (ret < 0) {
            LOGE( "Error while converting\n");
            break;
        }
        abuf_size = av_samples_get_buffer_size(&pMja->linesize, pMja->nb_channels,
                ret, pMja->sample_fmt, 1);
        if (abuf_size < 0) {
            LOGE( "Could not get sample buffer size\n");
            break;
        }
    }

详细

gist

你可能感兴趣的:(FFMPEG 解码和编码(编码mjpeg))