zoukankan      html  css  js  c++  java
  • 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!
    ");
    		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
    ");
    		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
    ");
    		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
    ");
    	   return -1;
       }
    	LOGI("dst_linesize:%d, dst_nb_channels:%d, dst_nb_samples:%d
    ", 
    			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)
    ", 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
    ");
    			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
    ");
    			break;
    		}
    	}
    

    详细

    gist

  • 相关阅读:
    小程序 wx.navigateTo和 wx.redirectTo区别
    小程序返回上一级页面背景音乐报错 setBackgroundAudioState:fail title is nil!;
    centos7 安装RabbitMQ3.6.15 以及各种报错
    MYSQL创建分区时候报错
    scrapy操作mysql/批量下载图片
    深入浅出TCP与IP协议笔记
    python反射详解
    python迭代器
    python生成器
    loggong模块
  • 原文地址:https://www.cnblogs.com/ikaka/p/4860858.html
Copyright © 2011-2022 走看看