ffmpeg yuv转h264 (mjpeg)流

不是纯原创,向雷神致敬,       还有问题,  转出来的视频播放到后面越来越差,cao,        好久都没写这方面的代码了。。。。。


/**

 * 最简单的基于FFmpeg的AVDevice例子(读取摄像头)
 * Simplest FFmpeg Device (Read Camera)
 *
 * 雷霄骅 Lei Xiaohua
 * [email protected]
 * 中国传媒大学/数字电视技术
 * Communication University of China / Digital TV Technology
 * http://blog.csdn.net/leixiaohua1020
 *
 * 本程序实现了本地摄像头数据的获取解码和显示。是基于FFmpeg
 * 的libavdevice类库最简单的例子。通过该例子,可以学习FFmpeg中
 * libavdevice类库的使用方法。
 * 本程序在Windows下可以使用2种方式读取摄像头数据:
 *  1.VFW: Video for Windows 屏幕捕捉设备。注意输入URL是设备的序号,
 *          从0至9。
 *  2.dshow: 使用Directshow。注意作者机器上的摄像头设备名称是
 *         “Integrated Camera”,使用的时候需要改成自己电脑上摄像头设
 *          备的名称。
 * 在Linux下则可以使用video4linux2读取摄像头设备。
 *
 * This software read data from Computer's Camera and play it.
 * It's the simplest example about usage of FFmpeg's libavdevice Library. 
 * It's suiltable for the beginner of FFmpeg.
 * This software support 2 methods to read camera in Microsoft Windows:
 *  1.gdigrab: VfW (Video for Windows) capture input device.
 *             The filename passed as input is the capture driver number,
 *             ranging from 0 to 9.
 *  2.dshow: Use Directshow. Camera's name in author's computer is 
 *             "Integrated Camera".
 * It use video4linux2 to read Camera in Linux.
 * 
 */




#include "stdafx.h"


extern "C"
{
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libswscale/swscale.h"
#include "libavdevice/avdevice.h"
#include "libavutil/imgutils.h"
//SDL
#include "sdl/SDL.h"
#include "sdl/SDL_thread.h"
};


//Output YUV420P 
#define OUTPUT_YUV420P 1




//'1' Use Dshow 
//'0' Use VFW
#define USE_DSHOW 1


//Show Device
void show_dshow_device(){
AVFormatContext *pFormatCtx = avformat_alloc_context();
AVDictionary* options = NULL;
av_dict_set(&options,"list_devices","true",0);
AVInputFormat *iformat = av_find_input_format("dshow");
printf("Device Info=============\n");
avformat_open_input(&pFormatCtx,"video=dummy",iformat,&options);
printf("========================\n");
}


//Show Device Option
void show_dshow_device_option(){
AVFormatContext *pFormatCtx = avformat_alloc_context();
AVDictionary* options = NULL;
av_dict_set(&options,"list_options","true",0);
AVInputFormat *iformat = av_find_input_format("dshow");
printf("Device Option Info======\n");
avformat_open_input(&pFormatCtx,"video=Integrated Camera",iformat,&options);
printf("========================\n");
}


//Show VFW Device
void show_vfw_device(){
AVFormatContext *pFormatCtx = avformat_alloc_context();
AVInputFormat *iformat = av_find_input_format("vfwcap");
printf("VFW Device Info======\n");
avformat_open_input(&pFormatCtx,"list",iformat,NULL);
printf("=====================\n");
}






int main(int argc, char* argv[])
{
int ret =0;
int   got_output;
AVCodecID codec_id=AV_CODEC_ID_H264;
char filename_out[]="test.h264";


FILE *fp_out;


AVFormatContext *pFormatCtx;
int i, videoindex;
AVCodecContext *pCodecCtx;
AVCodec *pCodec;
int framecnt=0;
av_register_all();
avformat_network_init();
pFormatCtx = avformat_alloc_context();


 AVPacket pkt;


AVCodec *pCodecEn;
AVCodecContext *pCodecCtxEn= NULL;


pCodecEn = avcodec_find_encoder(codec_id);
if (!pCodecEn) {
printf("Codec not found\n");
return -1;
}
pCodecCtxEn = avcodec_alloc_context3(pCodecEn);
if (!pCodecCtxEn) {
printf("Could not allocate video codec context\n");
return -1;
}





i=0;

//Open File
//char filepath[]="src01_480x272_22.h265";
//avformat_open_input(&pFormatCtx,filepath,NULL,NULL)


//Register Device
avdevice_register_all();
//Show Dshow Device
show_dshow_device();
//Show Device Options
show_dshow_device_option();
//Show VFW Options
show_vfw_device();
//Windows
#ifdef _WIN32
#if USE_DSHOW
AVInputFormat *ifmt=av_find_input_format("dshow");
//Set own video device's name
//if(avformat_open_input(&pFormatCtx,"video=Integrated Camera",ifmt,NULL)!=0){
// printf("Couldn't open input stream.(无法打开输入流)\n");
// return -1;
//}


if(avformat_open_input(&pFormatCtx,"video=DY-AF Camera",ifmt,NULL)!=0){                   //这是我测试的usb设备,你可能需要修改这个        你可以用directshow枚举出来
printf("Couldn't open input stream.(无法打开输入流)\n");
return -1;
}
#else
AVInputFormat *ifmt=av_find_input_format("vfwcap");
if(avformat_open_input(&pFormatCtx,"0",ifmt,NULL)!=0){
printf("Couldn't open input stream.(无法打开输入流)\n");
return -1;
}
#endif
#endif
//Linux
#ifdef linux
AVInputFormat *ifmt=av_find_input_format("video4linux2");
if(avformat_open_input(&pFormatCtx,"/dev/video0",ifmt,NULL)!=0){
printf("Couldn't open input stream.(无法打开输入流)\n");
return -1;
}
#endif




if(avformat_find_stream_info(pFormatCtx,NULL)<0)
{
printf("Couldn't find stream information.(无法获取流信息)\n");
return -1;
}
videoindex=-1;
for(i=0; inb_streams; i++) 
if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_VIDEO)
{
videoindex=i;
break;
}
if(videoindex==-1)
{
printf("Couldn't find a video stream.(没有找到视频流)\n");
return -1;
}
pCodecCtx=pFormatCtx->streams[videoindex]->codec;
pCodec=avcodec_find_decoder(pCodecCtx->codec_id);
if(pCodec==NULL)
{
printf("Codec not found.(没有找到解码器)\n");
return -1;
}
if(avcodec_open2(pCodecCtx, pCodec,NULL)<0)
{
printf("Could not open codec.(无法打开解码器)\n");
return -1;
}


//Output bitstream
fp_out = fopen(filename_out, "wb");
if (!fp_out) {
printf("Could not open %s\n", filename_out);
return -1;
}
AVFrame *pFrame,*pFrameYUV;
pFrame=avcodec_alloc_frame();
pFrameYUV=avcodec_alloc_frame();


pCodecCtxEn->bit_rate = 3000000; ;
pCodecCtxEn->width =  800;
pCodecCtxEn->height = 600;
pCodecCtxEn->time_base.num=1;
pCodecCtxEn->time_base.den=15;
pCodecCtxEn->gop_size = 12;
pCodecCtxEn->max_b_frames = 1;
pCodecCtxEn->pix_fmt = AV_PIX_FMT_YUV420P;


if (codec_id == AV_CODEC_ID_H264)
av_opt_set(pCodecCtxEn->priv_data, "preset", "slow", 0);


if (avcodec_open2(pCodecCtxEn, pCodecEn, NULL) < 0) {
printf("Could not open codec\n");
return -1;
}






//pFrameYUV->format = pCodecCtxEn->pix_fmt;
//pFrameYUV->width  = pCodecCtxEn->width;
//pFrameYUV->height = pCodecCtxEn->height;


uint8_t *out_buffer=(uint8_t *)av_malloc(avpicture_get_size(PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height));
avpicture_fill((AVPicture *)pFrameYUV, out_buffer, PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height);
//SDL----------------------------
if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER)) {  
printf( "Could not initialize SDL - %s\n", SDL_GetError()); 
return -1;

int screen_w=0,screen_h=0;
SDL_Surface *screen; 
screen_w = pCodecCtx->width;
screen_h = pCodecCtx->height;
screen = SDL_SetVideoMode(screen_w, screen_h, 0,0);


if(!screen) {  
printf("SDL: could not set video mode - exiting:%s\n",SDL_GetError());  
return -1;
}
SDL_Overlay *bmp; 
bmp = SDL_CreateYUVOverlay(pCodecCtx->width, pCodecCtx->height,SDL_YV12_OVERLAY, screen); 
SDL_Rect rect;
//SDL End------------------------
int got_picture;


AVPacket *packet=(AVPacket *)av_malloc(sizeof(AVPacket));
//Output Information-----------------------------
printf("File Information(文件信息)---------------------\n");
av_dump_format(pFormatCtx,0,NULL,0);
printf("-------------------------------------------------\n");





#if OUTPUT_YUV420P 
    //FILE *fp_yuv=fopen("output.yuv","wb+");  
#endif  


struct SwsContext *img_convert_ctx;
img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height, PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL); 
//------------------------------
while(av_read_frame(pFormatCtx, packet)>=0)
{
if(packet->stream_index==videoindex)
{
ret = avcodec_decode_video2(pCodecCtx, pFrame, &got_picture, packet);
if(ret < 0)
{
printf("Decode Error.(解码错误)\n");
return -1;
}




if(got_picture)
{
sws_scale(img_convert_ctx, (const uint8_t* const*)pFrame->data, pFrame->linesize, 0, pCodecCtx->height, pFrameYUV->data, pFrameYUV->linesize);

#if OUTPUT_YUV420P
int y_size=pCodecCtx->width*pCodecCtx->height;  
//fwrite(pFrameYUV->data[0],1,y_size,fp_yuv);    //Y 
//fwrite(pFrameYUV->data[1],1,y_size/4,fp_yuv);  //U
//fwrite(pFrameYUV->data[2],1,y_size/4,fp_yuv);  //V




av_init_packet(&pkt);
pkt.data = NULL;    // packet data will be allocated by the encoder
pkt.size = 0;


pFrame->pts = i++;
/* encode the image */
int ret = avcodec_encode_video2(pCodecCtxEn, &pkt, pFrameYUV, &got_output);
if (ret < 0) {
printf("Error encoding frame\n");
return -1;
}
if (got_output) {
printf("Succeed to encode frame: %5d\tsize:%5d\n",framecnt,pkt.size);
framecnt++;
fwrite(pkt.data, 1, pkt.size, fp_out);
av_free_packet(&pkt);
}




#endif
SDL_LockYUVOverlay(bmp);
bmp->pixels[0]=pFrameYUV->data[0];
bmp->pixels[2]=pFrameYUV->data[1];
bmp->pixels[1]=pFrameYUV->data[2];     
bmp->pitches[0]=pFrameYUV->linesize[0];
bmp->pitches[2]=pFrameYUV->linesize[1];   
bmp->pitches[1]=pFrameYUV->linesize[2];
SDL_UnlockYUVOverlay(bmp); 
rect.x = 0;    
rect.y = 0;    
rect.w = screen_w;    
rect.h = screen_h;  
SDL_DisplayYUVOverlay(bmp, &rect); 
//Delay 40ms
//SDL_Delay(40);
}
}
av_free_packet(packet);
}




//Flush Encoder
for (got_output = 1; got_output; i++) {
ret = avcodec_encode_video2(pCodecCtx, &pkt, NULL, &got_output);
if (ret < 0) {
printf("Error encoding frame\n");
return -1;
}
if (got_output) {
printf("Flush Encoder: Succeed to encode 1 frame!\tsize:%5d\n",pkt.size);
fwrite(pkt.data, 1, pkt.size, fp_out);
av_free_packet(&pkt);
}
}


fclose(fp_out);
sws_freeContext(img_convert_ctx);


#if OUTPUT_YUV420P 
   // fclose(fp_yuv);
#endif 


SDL_Quit();


av_free(out_buffer);
av_free(pFrameYUV);
avcodec_close(pCodecCtx);
avformat_close_input(&pFormatCtx);


return 0;
}

你可能感兴趣的:(FFMPEG)