您的位置:首页 > 其它

关于ffmpeg封装h264为mp4的问题

2015-06-15 20:40 330 查看
          照着ffmpeg里的例子封装h264为mp4的答题思路是对的,但是,还是要加一些东西才行~

下面是之前查东西的一些收获:

    对于h264文件来说,h264有两种封装,
    一种是annexb模式,传统模式,有startcode,SPS和PPS是在ES中
     一种是mp4模式,一般mp4 mkv会有,没有startcode,SPS和PPS以及其它信息被封装在container中,每一个frame前面是这个frame的长度
很多解码器只支持annexb这种模式,因此需要将mp4做转换:
在ffmpeg中用h264_mp4toannexb_filter可以做转换
实现:
注册filter
avcbsfc = av_bitstream_filter_init("h264_mp4toannexb");
转换bitstream
av_bitstream_filter_filter(AVBitStreamFilterContext *bsfc,
AVCodecContext *avctx, const char *args,
uint8_t **poutbuf, int *poutbuf_size,
const uint8_t *buf, int buf_size, int keyframe)

下面是我对视频封装具体代码:

#include "stdafx.h"

#ifndef INT64_C 

#define INT64_C(c) (c ## LL) 

#define UINT64_C(c) (c ## ULL) 

#endif 

#ifdef __MINGW32__

#undef main /* Prevents SDL from overriding main() */

#endif

#ifdef __cplusplus 

extern "C" {

#endif

#include "libavformat/avformat.h"

#include "libavcodec/avcodec.h"

#include "libswscale/swscale.h" 

#include "libavutil/imgutils.h"  

#include "libavutil/opt.h"    

#include "libavutil/mathematics.h"   

#include "libavutil/samplefmt.h"

#include "SDL\SDL.h"

#include "SDL\SDL_thread.h"

#ifdef __cplusplus 

}

#endif 

#include<ctime>

#include<iostream>

#include<windows.h>

#include<winsock.h>

using namespace std;

 #pragma comment(lib,"ws2_32.lib")

int main(int argc, char *argv[]) {

  AVFormatContext *pFormatCtx,*ofmt=NULL;

  pFormatCtx =avformat_alloc_context();

  int             i, videoStream,ret;

  AVCodecContext  *pCodecCtx;

  AVCodec         *pCodec;

  AVFrame         *pFrame,*pFrameYUV,*pFrameRGB; 

  SDL_Overlay     *bmp;

  SDL_Surface     *screen;

  SDL_Rect        rect;

  SDL_Event       event;

  av_register_all();

  avformat_network_init();

 // char *infile="udp://127.0.0.1:6666";

  char *infile="jl.h264";

  char *outname="lk.mp4";

  if(avformat_open_input(&pFormatCtx,infile,NULL,NULL)!=0)


cout<<"open file fails"<<endl;

     }

  if(avformat_find_stream_info(pFormatCtx,NULL)<0)
{
cout<<"find stream fails"<<endl;
}

   videoStream=-1;

   av_dump_format(pFormatCtx, 0, infile, false);

   for(i=0;i<pFormatCtx->nb_streams;i++)

   {
  if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_VIDEO)
  {
  videoStream=i;
  break;
  }

   }

   if(videoStream==-1)

   {
  cout<<"no video stream"<<endl;

   }

   pCodecCtx=pFormatCtx->streams[videoStream]->codec;

    //av_opt_set( pCodecCtx->priv_data, "preset", "superfast", 0);
// av_opt_set( pCodecCtx->priv_data, "tune", "zerolatency", 0);

   pCodec=avcodec_find_decoder(pCodecCtx->codec_id);

   if(pCodec==NULL)

   {
  cout<<"no find decoder"<<endl;
  return -1;

   }

   if(avcodec_open2(pCodecCtx,pCodec,NULL)<0)

   {
  cout<< "open decoder fails"<<endl;
  return -1;

   }

   //为解码帧分配内存

   pFrame=avcodec_alloc_frame();

   pFrameYUV=avcodec_alloc_frame();

   pFrameRGB=avcodec_alloc_frame();

   //根据像素格式和分辨率获得图片所需空间大小

   uint8_t *out_buffer,*rgb_buffer;

   out_buffer=new uint8_t[avpicture_get_size(PIX_FMT_YUV420P,pCodecCtx->width,pCodecCtx->height)];

    rgb_buffer=new uint8_t[avpicture_get_size(PIX_FMT_RGB24,pCodecCtx->width,pCodecCtx->height)];

   avpicture_fill((AVPicture*)pFrameYUV,out_buffer,PIX_FMT_YUV420P,pCodecCtx->width,pCodecCtx->height);

    avpicture_fill((AVPicture*)pFrameRGB,rgb_buffer,PIX_FMT_RGB24,pCodecCtx->width,pCodecCtx->height);

   bool quit=false;

//   SDL_Event event;

   if(SDL_Init(SDL_INIT_EVENTTHREAD))

   {
  cout<<"init SDL fails"<<endl;
  return -1;

   }

   //建立一个指定宽度高度的窗口

//   SDL_Surface *screen;

   screen=SDL_SetVideoMode(pCodecCtx->width,pCodecCtx->height,0,0);

   if(!screen)

   {
  cout<<"build screen fails"<<endl;
  return -1;

   }

   //在屏幕上创建一个yuv覆盖。一边我们输入视频

//   SDL_Overlay *bmp;

   bmp=SDL_CreateYUVOverlay(pCodecCtx->width,pCodecCtx->height,SDL_YV12_OVERLAY,screen);

   //定义数据包

   int y_size=pCodecCtx->width*pCodecCtx->height;

   AVPacket* packet=(AVPacket*)av_malloc(sizeof(AVPacket));

   if(av_new_packet(packet,y_size))

   {
  cout<<"av_new_packet fails"<<endl;
  return -1;

   }

   //根据编码信息设置渲染格式

   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);

    struct SwsContext *img_convert_rgb;

   img_convert_rgb=sws_getContext(pCodecCtx->width,pCodecCtx->height,pCodecCtx->pix_fmt,pCodecCtx->width,pCodecCtx->height,PIX_FMT_RGB24,SWS_BICUBIC,NULL,NULL,NULL);

   

   //不停地从码流中提取帧数据,存放到数据包,并且判断用户是否要退出

   int got_picture;

   int kk=0;

     AVStream *in_stream,*out_stream;

   //输出设置

   avformat_alloc_output_context2(&ofmt,NULL,"mp4",outname);

   if(!ofmt)

   {
  cout<<"creat output fails"<<endl;
  exit(1);

   }

   
  in_stream=pFormatCtx->streams[0];
  
  out_stream=avformat_new_stream(ofmt,in_stream->codec->codec);
  if(!out_stream)
  {
  cout<<"out_stream build fails"<<endl;
  exit(1);
  }
  int ret1=avcodec_copy_context(out_stream->codec,in_stream->codec);
  if(ret1<0)
  {
  cout<<"copy_context fails"<<endl;
  }
  out_stream->codec->codec_tag=0;
  out_stream->r_frame_rate.num=25;
  out_stream->r_frame_rate.den=1;
  if(ofmt->oformat->flags & AVFMT_GLOBALHEADER)
 {
out_stream->codec->flags|=CODEC_FLAG_GLOBAL_HEADER;
 }     

      
ret=avio_open(&ofmt->pb,outname,AVIO_FLAG_WRITE);
if(ret<0)
{
cout<<"could not open outfile"<<endl;
}

       
//av_dump_format(ofmt, 0, outname, false);

int frame_index=0;

//FILE *fp=fopen("df.h264","ab");
ret =avformat_write_header(ofmt,NULL);
if(ret<0)
 {
  cout<<"avformat_write_header fails"<<endl;  
 }

int key=0;

AVBitStreamFilterContext* h264bsfc =  av_bitstream_filter_init("h264_mp4toannexb"); 

 while(av_read_frame(pFormatCtx,packet)>=0 && quit==false)

      {
 //in=pFormatCtx->streams[packet->stream_index];
// out=ofmt->streams[packet->stream_index];
// ret=av_interleaved_write_frame(ofmt,packet);

 av_bitstream_filter_filter(h264bsfc, in_stream->codec, NULL, &(packet->data), &(packet->size), packet->data, packet->size, 0);
 if(packet->stream_index==videoStream)
 {
 ret=avcodec_decode_video2(pCodecCtx,pFrame,&got_picture,packet);

 
//  cout<<"receive:"<<packet->pts<<endl;
 if(ret<0)
 {
 cout<<"decode fails"<<endl;
 //return -1;
 }
 if((got_picture)&&(ret>0))
 {
/* pFrame->data[0] += pFrame->linesize[0] * (pCodecCtx->height - 1);

                 pFrame->linesize[0] *= -1; 

                 pFrame->data[1] += pFrame->linesize[1] * (pCodecCtx->height / 2 - 1);

                 pFrame->linesize[1] *= -1;

                pFrame->data[2] += pFrame->linesize[2] * (pCodecCtx->height / 2 - 1);

             pFrame->linesize[2] *= -1;*/
 sws_scale(img_convert_ctx,(const uint8_t *const*)pFrame->data,pFrame->linesize,0,pCodecCtx->height,pFrameYUV->data,pFrameYUV->linesize);
 sws_scale(img_convert_rgb,(const uint8_t *const*)pFrame->data,pFrame->linesize,0,pCodecCtx->height,pFrameRGB->data,pFrameRGB->linesize);
 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 用于显示SDL_Overlay显示的位置
 rect.x=0;
 rect.y=0;
 rect.w=pCodecCtx->width;
 rect.h=pCodecCtx->height;
 SDL_DisplayYUVOverlay(bmp,&rect);
SDL_Delay(40);//延迟40ms相当于25帧每秒
 while(SDL_PollEvent(&event))
 {
 if(event.type==SDL_QUIT)
 quit=true;
 }
 

//Write PTS

AVRational time_base1=in_stream->time_base;
//Duration between 2 frames (us)
int64_t calc_duration=(double)AV_TIME_BASE/av_q2d(in_stream->r_frame_rate);
//Parameters
packet->pts=(double)(frame_index*calc_duration)/(double)(av_q2d(time_base1)*AV_TIME_BASE);
packet->dts=packet->pts;
packet->duration=(double)calc_duration/(double)(av_q2d(time_base1)*AV_TIME_BASE);
frame_index++;
       
/* copy packet */
//转换PTS/DTS(Convert PTS/DTS)
 
packet->pts = av_rescale_rnd(packet->pts, out_stream->time_base.den,in_stream->time_base.den,AV_ROUND_NEAR_INF);
packet->dts = av_rescale_rnd(packet->dts, out_stream->time_base.den,in_stream->time_base.den,AV_ROUND_NEAR_INF);
packet->duration = av_rescale_q(packet->duration, in_stream->time_base,out_stream->time_base);
packet->pos = -1;
packet->stream_index=0;
/*
FILE *fp1=fopen("ff.h264","wb");
fwrite(packet->data,1,packet->size,fp1);
fclose(fp1);

FILE *fp2=fopen("ff1.h264","wb");
fwrite(packet->data,1,packet->size,fp2);
fclose(fp2);*/
packet->flags |=AV_PKT_FLAG_KEY;

                 //用了此句就不用bitstream,AVBitStreamFilterContext
//写入(Write)
if (av_interleaved_write_frame(ofmt, packet) < 0)
{
printf( "Error muxing packet\n");
break;
}

printf("Write 1 Packet. size:%5d\tpts:%8d\n",packet->size,packet->pts);

 
}
}
 av_free_packet(packet);

   }

   //fclose(fp);

  av_write_trailer(ofmt);

    SDL_Quit();
sws_freeContext(img_convert_ctx);
delete []out_buffer;
av_free(pFrameYUV);
avcodec_close(pCodecCtx);
av_close_input_file(pFormatCtx);

return 0;

}

   //***************输出配置start

   

  /*

   avformat_alloc_output_context2(&ofmt,NULL,"h264",outname);

   if(!ofmt)

   {
  cout<<"create output context fails"<<endl;
  exit(1);

   }

   for(int j=0;j<pFormatCtx->nb_streams;j++)

   { 
  AVStream *in_stream=pFormatCtx->streams[j];
  AVStream *out_stream=avformat_new_stream(ofmt,in_stream->codec->codec);
  if(!out_stream)
  {
  cout<<"out_stream build fails"<<endl;
   }
  ret=avcodec_copy_context(out_stream->codec,in_stream->codec);
  if(ret<0)
  {
  cout<<"copy_context fails"<<endl;
  }
  out_stream->codec->codec_tag=0;
  out_stream->r_frame_rate.num=25;
  out_stream->r_frame_rate.den=1;
  if(ofmt->oformat->flags & AVFMT_GLOBALHEADER)
  {
  out_stream->codec->flags|=CODEC_FLAG_GLOBAL_HEADER;
  }     

   }

   ret=avio_open(&ofmt->pb,outname,AVIO_FLAG_WRITE);

   if(ret<0)

   {
  cout<<"could not open outfile"<<endl;

   }

   //av_dump_format(ofmt, 0, outname, false);

   ret =avformat_write_header(ofmt,NULL);

   if(ret<0)

     {

     cout<<"avformat_write_header fails"<<endl;  

     }

//   AVStream *in,*out;

*/

   //**************输出配置end
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: