您的位置:首页 > 其它

实战小项目之基于嵌入式的图像采集压缩保存

2017-01-20 15:10 411 查看
项目简介

  这是之前图像采集显示程序的升级版,首先基础部分的图像v4l2采集、framebuffer显示、IPU转码都进行了c++封装,之后加入了以下新功能:

SDL1.2显示

FFmpeg编码保存版本一(顺序执行)

FFmpeg编码保存版本二(线程方式)  

c++ pthread库简单封装

  这个小工程是一个附属产品,boss的项目中用到了图像编码保存,然后学了一段时间的多媒体技术(主要就是FFmpeg),后来就衍生出了这个版本的程序

  不多说,上代码

  首先是SDL显示部分

/*
* EncodeSaver2.cpp
*
*  Created on: Oct 12, 2016
*      Author: tla001
*/

#include "EncodeSaver2.h"

EncodeSaver2::EncodeSaver2(int in_w,int in_h,int out_w,int out_h,char* out_file) {
// TODO Auto-generated constructor stub
this->in_w=in_w;
this->in_h=in_h;
this->out_w=out_w;
this->out_h=out_h;
this->framesize=0;
this->out_file=out_file;
this->basicsize=in_w*in_h;
this->frameNum=0;
this->ready=0;
}

EncodeSaver2::~EncodeSaver2() {
// TODO Auto-generated destructor stub
closeDevice();
}

int EncodeSaver2::initDevice()
{
av_register_all();
//方法1.组合使用几个函数
pFormatCtx = avformat_alloc_context();
//猜格式
fmt = av_guess_format(NULL, out_file, NULL);
pFormatCtx->oformat = fmt;
if (avio_open(&pFormatCtx->pb,out_file, AVIO_FLAG_READ_WRITE) < 0)
{
printf("输出文件打开失败");
return -1;
}

video_st = av_new_stream(pFormatCtx, 0);
if (video_st==NULL)
{
return -1;
}
pCodecCtx = video_st->codec;
pCodecCtx->codec_id = fmt->video_codec;
pCodecCtx->codec_type = AVMEDIA_TYPE_VIDEO;
pCodecCtx->pix_fmt = PIX_FMT_YUV420P;
pCodecCtx->width = in_w;
pCodecCtx->height = in_h;
pCodecCtx->time_base.num = 1;
pCodecCtx->time_base.den = 25;
pCodecCtx->bit_rate = 400000;
pCodecCtx->gop_size=250;
//设置
video_st->time_base.num=1;
video_st->time_base.den=25;
//H264
pCodecCtx->me_range = 16;
pCodecCtx->max_qdiff = 4;
pCodecCtx->qmin = 10;
pCodecCtx->qmax = 51;
pCodecCtx->qcompress = 0.6;
if (pCodecCtx->codec_id == CODEC_ID_MPEG2VIDEO)
{
pCodecCtx->max_b_frames = 2;
}
if (pCodecCtx->codec_id == CODEC_ID_MPEG1VIDEO)
{
pCodecCtx->mb_decision = 2;
}
if (!strcmp(pFormatCtx->oformat->name, "mp4") || !strcmp(pFormatCtx->oformat->name, "mov") || !strcmp(pFormatCtx->oformat->name, "3gp"))
{
pCodecCtx->flags |= CODEC_FLAG_GLOBAL_HEADER;
}
//输出格式信息
av_dump_format(pFormatCtx, 0, out_file, 1);

pCodec = avcodec_find_encoder(pCodecCtx->codec_id);
if (!pCodec)
{
printf("没有找到合适的编码器!\n");
return -1;
}
if (avcodec_open2(pCodecCtx, pCodec,NULL) < 0)
{
printf("编码器打开失败!\n");
return -1;
}
//输出420

picture = avcodec_alloc_frame();
framesize = avpicture_get_size(PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height);
picture_buf = (uint8_t *)av_malloc(framesize);
avpicture_fill((AVPicture *)picture, picture_buf, PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height);
//输入422
picture422 = avcodec_alloc_frame();
framesize422 = avpicture_get_size(PIX_FMT_YUYV422, pCodecCtx->width, pCodecCtx->height);
picture422_buf = (uint8_t *)av_malloc(framesize422);
avpicture_fill((AVPicture *)picture422, picture422_buf, PIX_FMT_YUYV422, pCodecCtx->width, pCodecCtx->height);
img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height, PIX_FMT_YUYV422, pCodecCtx->width, pCodecCtx->height, PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL);
//写文件头
avformat_write_header(pFormatCtx,NULL);
av_new_packet(&pkt,basicsize*3);

this->start();
cout<<"thread start"<<endl;
}
int EncodeSaver2::closeDevice()
{
this->stop();
int ret = flush_encoder(pFormatCtx,0);
if (ret < 0) {
printf("Flushing encoder failed\n");
return -1;
}

//写文件尾
av_write_trailer(pFormatCtx);

//清理
if (video_st)
{
avcodec_close(video_st->codec);
av_free(picture);
av_free(picture_buf);
av_free(picture422);
av_free(picture422_buf);
}
avio_close(pFormatCtx->pb);
avformat_free_context(pFormatCtx);
return 0;
}
int EncodeSaver2::doEncode(unsigned char *buf)
{
int ret=0;
//422
memcpy(picture422_buft.a,buf,basicsize*2);
//picture422_bufs.push(picture422_buft);
this->ready=1;
return ret;
}
int EncodeSaver2::isReady(){
return ready;
}
void EncodeSaver2::run(){
int ret;
struct timeval temp;
temp.tv_sec = 0;
temp.tv_usec = 40000000;//40ms
printf("thread is up!\n");
while(1){
if(isStop())
pthread_exit(0);
if(isStart()&&isReady()){
//        printf("here 1\n");
//        sleep(1);

//select(0, NULL, NULL, NULL, &temp);
//usleep(40000000);
printf("**********time up********ttkf*** \n");
//    if(picture422_bufs.empty()){
//        cout<<" queue empty"<<endl;
//        continue;
//    }

//picture422_buf=picture422_bufs.front().a;
//picture422_bufs.pop();
memcpy(picture422_buf,picture422_buft.a,basicsize*2);
picture422->data[0] = picture422_buf;
sws_scale(img_convert_ctx, picture422->data, picture422->linesize, 0, pCodecCtx->height, picture->data, picture->linesize);
//PTS
if (pFormatCtx->oformat->flags & AVFMT_RAWPICTURE)
{
AVPacket pkt;
av_init_packet(&pkt);
pkt.flags |= AV_PKT_FLAG_KEY;
pkt.stream_index = video_st->index;
pkt.data = (uint8_t*)picture;
pkt.size = sizeof(AVPicture);
ret = av_write_frame(pFormatCtx, &pkt);
}
else{
int out_size = avcodec_encode_video(pCodecCtx, picture_buf, framesize, picture);
if (out_size > 0)
{
AVPacket pkt;
av_init_packet(&pkt);
pkt.pts = av_rescale_q(pCodecCtx->coded_frame->pts, pCodecCtx->time_base, video_st->time_base);
if (pCodecCtx->coded_frame->key_frame)
{
pkt.flags |= AV_PKT_FLAG_KEY;
}
pkt.stream_index = video_st->index;
pkt.data = picture_buf;
pkt.size = out_size;
ret = av_write_frame(pFormatCtx, &pkt);
}
}
}else{
printf("ready for data\n");
usleep(50000);//线程起来之后,由于参数没准备好,可能会空转
}
}
}
int EncodeSaver2::flush_encoder(AVFormatContext *fmt_ctx,unsigned int stream_index)
{
int ret;
int got_frame;
AVPacket enc_pkt;
if (!(fmt_ctx->streams[stream_index]->codec->codec->capabilities &
CODEC_CAP_DELAY))
return 0;
while (1) {
printf("Flushing stream #%u encoder\n", stream_index);
//ret = encode_write_frame(NULL, stream_index, &got_frame);
enc_pkt.data = NULL;
enc_pkt.size = 0;
av_init_packet(&enc_pkt);
ret = avcodec_encode_video2 (fmt_ctx->streams[stream_index]->codec, &enc_pkt,
NULL, &got_frame);
av_frame_free(NULL);
if (ret < 0)
break;
if (!got_frame)
{ret=0;break;}
printf("successed frame!\n");
/* mux encoded frame */
ret = av_write_frame(fmt_ctx, &enc_pkt);
if (ret < 0)
break;
}
return ret;
}


View Code

完整工程
https://github.com/tla001/CapTransV2
相关链接  

ffmpeg移植

  http://www.cnblogs.com/tla001/p/5906220.html

音视频处理(FFmpeg)基础

  http://blog.csdn.net/leixiaohua1020/article/details/15811977

  学习的资料,基本都是从雷神的博客中来的

相关命令

ffmpeg -f video4linux2 -i /dev/video0 -vcodec libx264 -s 320*240 -r 10 video0.mkv
ffmpeg -f video4linux2 -s 640*480 -r 25 -i /dev/video0 test.avi
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: