分享

ffmpeg处理rtmp/文件/rtsp的推流和拉流

 WindySky 2018-03-07
 https://www.cnblogs.com/lidabo/p/6932134.html
本demo演示了利用ffmpeg从服务器拉流或本地文件读取流,更改流url或文件类型名称发送回服务器或存到本地的作用。由于本程序只写了3个小时,还要忙别的,所以会有一些bug和优化的地方。不过demo的意义已经达到了。 [cpp] view plain copy //info.h  #ifndef __INFO_H__  #define __INFO_H__    #include    #include     #endif  [cpp] view plain copy //ffmpeg.h  #ifndef __FFMPEG_H__  #define __FFMPEG_H__    #include "info.h"    extern "C"  {  #include "libavformat/avformat.h"  #include "libavformat/avio.h"  #include "libavcodec/avcodec.h"  #include "libswscale/swscale.h"  #include "libavutil/avutil.h"  #include "libavutil/mathematics.h"  #include "libswresample/swresample.h"  #include "libavutil/opt.h"  #include "libavutil/channel_layout.h"  #include "libavutil/samplefmt.h"  #include "libavdevice/avdevice.h"  //摄像头所用  #include "libavfilter/avfilter.h"  #include "libavutil/error.h"  #include "libavutil/mathematics.h"    #include "libavutil/time.h"    #include "inttypes.h"  #include "stdint.h"  };    #pragma comment(lib,"avformat.lib")  #pragma comment(lib,"avcodec.lib")  #pragma comment(lib,"avdevice.lib")  #pragma comment(lib,"avfilter.lib")  #pragma comment(lib,"avutil.lib")  #pragma comment(lib,"postproc.lib")  #pragma comment(lib,"swresample.lib")  #pragma comment(lib,"swscale.lib")      //#define INPUTURL   "test.flv"   #define INPUTURL     "rtmp://test1.com:1935/myapp/teststream1"   //#define OUTPUTURL  "testnew.flv";   #define OUTPUTURL    "rtmp://test1.com:1935/myapp/teststream1new"    //video param  extern int m_dwWidth;  extern int m_dwHeight;  extern double m_dbFrameRate;  //帧率                                                    extern AVCodecID video_codecID;  extern AVPixelFormat video_pixelfromat;  extern char spspps[100];  extern int spspps_size;    //audio param  extern int m_dwChannelCount; //声道  extern int m_dwBitsPerSample; //样本  extern int m_dwFrequency;     //采样率  extern AVCodecID audio_codecID;  extern int audio_frame_size;    #define AUDIO_ID            0                                                 //packet 中的ID ,如果先加入音频 pocket 则音频是 0  视频是1,否则相反  #define VEDIO_ID            1    extern int nRet;                                                              //状态标志  extern AVFormatContext* icodec;   extern AVInputFormat* ifmt;  extern char szError[256];                                                     //错误字符串  extern AVFormatContext* oc ;                                                  //输出流context  extern AVOutputFormat* ofmt;  extern AVStream* video_st;  extern AVStream* audio_st;  extern AVCodec *audio_codec;  extern AVCodec *video_codec;  extern int video_stream_idx;  extern int audio_stream_idx;  extern AVPacket pkt;     extern AVBitStreamFilterContext * vbsf_aac_adtstoasc;                         //aac->adts to asc过滤器  static int  m_nVideoTimeStamp = 0;  static int  m_nAudioTimeStamp = 0;    int InitInput(char * Filename,AVFormatContext ** iframe_c,AVInputFormat** iinputframe);  int InitOutput();  AVStream * Add_output_stream_2(AVFormatContext* output_format_context,AVMediaType codec_type_t, AVCodecID codecID,AVCodec **codec);   int OpenCodec(AVStream * istream, AVCodec * icodec); //打开编解码器  void read_frame(AVFormatContext *oc);    //从文件读取一帧数据根据ID读取不同的帧  void write_frame_3(AVFormatContext *oc,int ID,AVPacket pkt_t); //这个是根据传过来的buf 和size 写入文件  int Es2Mux_2(); //通过时间戳控制写入音视频帧顺序  int UintInput();  int UintOutput();    #endif   [cpp] view plain copy //ffmpeg.cpp  #include "ffmpeg.h"    int nRet = 0;  AVFormatContext* icodec = NULL;   AVInputFormat* ifmt = NULL;  char szError[256];   AVFormatContext* oc = NULL;  AVOutputFormat* ofmt = NULL;  AVStream * video_st = NULL;  AVStream * audio_st = NULL;  AVCodec *audio_codec;  AVCodec *video_codec;  double audio_pts = 0.0;  double video_pts = 0.0;  int video_stream_idx = -1;  int audio_stream_idx = -1;  AVPacket pkt;  AVBitStreamFilterContext * vbsf_aac_adtstoasc = NULL;    //video param  int m_dwWidth = 0;  int m_dwHeight = 0;  double m_dbFrameRate = 25.0;  //帧率                                                    AVCodecID video_codecID = AV_CODEC_ID_H264;  AVPixelFormat video_pixelfromat = AV_PIX_FMT_YUV420P;  char spspps[100];  int spspps_size = 0;    //audio param  int m_dwChannelCount = 2;      //声道  int m_dwBitsPerSample = 16;    //样本  int m_dwFrequency = 44100;     //采样率  AVCodecID audio_codecID = AV_CODEC_ID_AAC;  int audio_frame_size  = 1024;      int InitInput(char * Filename,AVFormatContext ** iframe_c,AVInputFormat** iinputframe)  {      int i = 0;      nRet = avformat_open_input(iframe_c, Filename,(*iinputframe), NULL);      if (nRet != 0)      {          av_strerror(nRet, szError, 256);          printf(szError);          printf("\n");          printf("Call avformat_open_input function failed!\n");          return 0;      }      if (av_find_stream_info(*iframe_c) < 0)      {          printf("Call av_find_stream_info function failed!\n");          return 0;      }      //输出视频信息      av_dump_format(*iframe_c, -1, Filename, 0);        //添加音频信息到输出context      for (i = 0; i < (*iframe_c)->nb_streams; i++)      {          if ((*iframe_c)->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)          {              video_stream_idx = i;              m_dwWidth = (*iframe_c)->streams[i]->codec->width;              m_dwHeight = (*iframe_c)->streams[i]->codec->height;              m_dbFrameRate = av_q2d((*iframe_c)->streams[i]->r_frame_rate);              video_codecID = (*iframe_c)->streams[i]->codec->codec_id;              video_pixelfromat = (*iframe_c)->streams[i]->codec->pix_fmt;              spspps_size = (*iframe_c)->streams[i]->codec->extradata_size;              memcpy(spspps,(*iframe_c)->streams[i]->codec->extradata,spspps_size);          }          else if ((*iframe_c)->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO)          {              audio_stream_idx = i;              m_dwChannelCount = (*iframe_c)->streams[i]->codec->channels;              switch ((*iframe_c)->streams[i]->codec->sample_fmt)              {              case AV_SAMPLE_FMT_U8:                  m_dwBitsPerSample  = 8;                  break;              case AV_SAMPLE_FMT_S16:                  m_dwBitsPerSample  = 16;                  break;              case AV_SAMPLE_FMT_S32:                  m_dwBitsPerSample  = 32;                  break;              default:                  break;              }              m_dwFrequency = (*iframe_c)->streams[i]->codec->sample_rate;              audio_codecID = (*iframe_c)->streams[i]->codec->codec_id;              audio_frame_size = (*iframe_c)->streams[i]->codec->frame_size;          }      }      return 1;  }    int InitOutput()  {      int i = 0;      /* allocate the output media context */      avformat_alloc_output_context2(&oc, NULL, "flv", OUTPUTURL);      if (!oc)       {          return getchar();      }      ofmt = oc->oformat;        /* open the output file, if needed */      if (!(ofmt->flags & AVFMT_NOFILE))      {          if (avio_open(&oc->pb, OUTPUTURL, AVIO_FLAG_WRITE) < 0)          {              printf("Could not open '%s'\n", OUTPUTURL);              return getchar();          }      }        //添加音频信息到输出context      if(audio_stream_idx != -1)      {          ofmt->audio_codec = audio_codecID;          audio_st = Add_output_stream_2(oc, AVMEDIA_TYPE_AUDIO,audio_codecID,&audio_codec);      }        //添加视频信息到输出context      ofmt->video_codec = video_codecID;      video_st = Add_output_stream_2(oc, AVMEDIA_TYPE_VIDEO,video_codecID,&video_codec);        if (OpenCodec(video_st,video_codec) < 0)   //打开视频编码器      {          printf("can not open video codec\n");          return getchar();      }        if(audio_stream_idx != -1)      {          if (OpenCodec(audio_st,audio_codec) < 0)   //打开音频编码器          {              printf("can not open audio codec\n");              return getchar();          }      }        av_dump_format(oc, 0, OUTPUTURL, 1);        if (avformat_write_header(oc, NULL))      {          printf("Call avformat_write_header function failed.\n");          return 0;      }        if(audio_stream_idx != -1)      {          if ((strstr(oc->oformat->name, "flv") != NULL) ||               (strstr(oc->oformat->name, "mp4") != NULL) ||               (strstr(oc->oformat->name, "mov") != NULL) ||              (strstr(oc->oformat->name, "3gp") != NULL))              {              if (audio_st->codec->codec_id == AV_CODEC_ID_AAC) //AV_CODEC_ID_AAC              {                  vbsf_aac_adtstoasc =  av_bitstream_filter_init("aac_adtstoasc");                }          }       }      if(vbsf_aac_adtstoasc == NULL)        {            return -1;        }       return 1;  }    AVStream * Add_output_stream_2(AVFormatContext* output_format_context,AVMediaType codec_type_t, AVCodecID codecID,AVCodec **codec)  {      AVCodecContext* output_codec_context = NULL;      AVStream * output_stream = NULL;        /* find the encoder */      *codec = avcodec_find_encoder(codecID);      if (!(*codec))       {          return NULL;      }      output_stream = avformat_new_stream(output_format_context, *codec);      if (!output_stream)      {          return NULL;      }        output_stream->id = output_format_context->nb_streams - 1;      output_codec_context = output_stream->codec;      output_codec_context->codec_id = codecID;      output_codec_context->codec_type = codec_type_t;        switch (codec_type_t)      {      case AVMEDIA_TYPE_AUDIO:          AVRational CodecContext_time_base;          CodecContext_time_base.num = 1;          CodecContext_time_base.den = m_dwFrequency;          output_stream->time_base = CodecContext_time_base;          output_codec_context->time_base = CodecContext_time_base;          output_stream->start_time = 0;          output_codec_context->sample_rate = m_dwFrequency;          output_codec_context->channels = m_dwChannelCount;          output_codec_context->frame_size = audio_frame_size;          switch (m_dwBitsPerSample)          {          case 8:              output_codec_context->sample_fmt  = AV_SAMPLE_FMT_U8;              break;          case 16:              output_codec_context->sample_fmt  = AV_SAMPLE_FMT_S16;              break;          case 32:              output_codec_context->sample_fmt  = AV_SAMPLE_FMT_S32;              break;          default:              break;          }          output_codec_context->block_align = 0;          if(! strcmp( output_format_context-> oformat-> name,  "mp4" ) ||              !strcmp (output_format_context ->oformat ->name , "mov" ) ||              !strcmp (output_format_context ->oformat ->name , "3gp" ) ||              !strcmp (output_format_context ->oformat ->name , "flv" ))          {              output_codec_context->flags |= CODEC_FLAG_GLOBAL_HEADER;          }          break;      case AVMEDIA_TYPE_VIDEO:          AVRational r_frame_rate_t;          r_frame_rate_t.num = 1000;          r_frame_rate_t.den = (int)(m_dbFrameRate * 1000);          output_stream->time_base = r_frame_rate_t;          output_codec_context->time_base = r_frame_rate_t;            AVRational r_frame_rate_s;          r_frame_rate_s.num = (int)(m_dbFrameRate * 1000);          r_frame_rate_s.den = 1000;          output_stream->r_frame_rate = r_frame_rate_s;            output_stream->start_time = 0;          output_codec_context->pix_fmt = video_pixelfromat;          output_codec_context->width = m_dwWidth;          output_codec_context->height = m_dwHeight;          output_codec_context->extradata = (uint8_t *)spspps;          output_codec_context->extradata_size = spspps_size;          //这里注意不要加头,demux的时候 h264filter过滤器会改变文件本身信息          //这里用output_codec_context->extradata 来显示缩略图          //if(! strcmp( output_format_context-> oformat-> name,  "mp4" ) ||          //  !strcmp (output_format_context ->oformat ->name , "mov" ) ||          //  !strcmp (output_format_context ->oformat ->name , "3gp" ) ||          //  !strcmp (output_format_context ->oformat ->name , "flv" ))          //{          //  output_codec_context->flags |= CODEC_FLAG_GLOBAL_HEADER;          //}          break;      default:          break;      }      return output_stream;  }    int OpenCodec(AVStream * istream, AVCodec * icodec)  {      AVCodecContext *c = istream->codec;      nRet = avcodec_open2(c, icodec, NULL);       return nRet;  }    int UintInput()  {      /* free the stream */      av_free(icodec);      return 1;  }    int UintOutput()  {      int i = 0;      nRet = av_write_trailer(oc);      if (nRet < 0)      {          av_strerror(nRet, szError, 256);          printf(szError);          printf("\n");          printf("Call av_write_trailer function failed\n");      }      if (vbsf_aac_adtstoasc !=NULL)      {          av_bitstream_filter_close(vbsf_aac_adtstoasc);           vbsf_aac_adtstoasc = NULL;      }      av_dump_format(oc, -1, OUTPUTURL, 1);       /* Free the streams. */      for (i = 0; i < oc->nb_streams; i++)       {          av_freep(&oc->streams[i]->codec);          av_freep(&oc->streams[i]);      }      if (!(ofmt->flags & AVFMT_NOFILE))      {          /* Close the output file. */          avio_close(oc->pb);      }      av_free(oc);      return 1;  }    void read_frame(AVFormatContext *oc)  {      int ret = 0;        ret = av_read_frame(icodec, &pkt);        if (pkt.stream_index == video_stream_idx)      {          write_frame_3(oc,VEDIO_ID,pkt);      }      else if (pkt.stream_index == audio_stream_idx)      {          write_frame_3(oc,AUDIO_ID,pkt);      }  }    void write_frame_3(AVFormatContext *oc,int ID,AVPacket pkt_t)  {      int64_t pts = 0, dts = 0;      int nRet = -1;      AVRational time_base_t;      time_base_t.num = 1;      time_base_t.den = 1000;        if(ID == VEDIO_ID)      {          AVPacket videopacket_t;          av_init_packet(&videopacket_t);            if (av_dup_packet(&videopacket_t) < 0)          {              av_free_packet(&videopacket_t);          }            videopacket_t.pts = pkt_t.pts;          videopacket_t.dts = pkt_t.dts;          videopacket_t.pos = 0;          videopacket_t.priv = 0;          videopacket_t.flags = 1;          videopacket_t.convergence_duration = 0;          videopacket_t.side_data_elems = 0;          videopacket_t.stream_index = VEDIO_ID;          videopacket_t.duration = 0;          videopacket_t.data = pkt_t.data;          videopacket_t.size = pkt_t.size;          nRet = av_interleaved_write_frame(oc, &videopacket_t);          if (nRet != 0)          {              printf("error av_interleaved_write_frame _ video\n");          }          av_free_packet(&videopacket_t);      }      else if(ID == AUDIO_ID)      {          AVPacket audiopacket_t;          av_init_packet(&audiopacket_t);            if (av_dup_packet(&audiopacket_t) < 0)          {              av_free_packet(&audiopacket_t);          }            audiopacket_t.pts = pkt_t.pts;          audiopacket_t.dts = pkt_t.dts;          audiopacket_t.pos = 0;          audiopacket_t.priv = 0;          audiopacket_t.flags = 1;          audiopacket_t.duration = 0;          audiopacket_t.convergence_duration = 0;          audiopacket_t.side_data_elems = 0;          audiopacket_t.stream_index = AUDIO_ID;          audiopacket_t.duration = 0;          audiopacket_t.data = pkt_t.data;          audiopacket_t.size = pkt_t.size;            //添加过滤器          if(! strcmp( oc-> oformat-> name,  "mp4" ) ||              !strcmp (oc ->oformat ->name , "mov" ) ||              !strcmp (oc ->oformat ->name , "3gp" ) ||              !strcmp (oc ->oformat ->name , "flv" ))          {              if (audio_st->codec->codec_id == AV_CODEC_ID_AAC)              {                  if (vbsf_aac_adtstoasc != NULL)                  {                      AVPacket filteredPacket = audiopacket_t;                       int a = av_bitstream_filter_filter(vbsf_aac_adtstoasc,                                                                     audio_st->codec, NULL,&filteredPacket.data, &filteredPacket.size,                          audiopacket_t.data, audiopacket_t.size, audiopacket_t.flags & AV_PKT_FLAG_KEY);                       if (a >  0)                                   {                                          av_free_packet(&audiopacket_t);                           filteredPacket.destruct = av_destruct_packet;                            audiopacket_t = filteredPacket;                                   }                         else if (a == 0)                      {                          audiopacket_t = filteredPacket;                         }                      else if (a < 0)                                  {                                          fprintf(stderr, "%s failed for stream %d, codec %s",                              vbsf_aac_adtstoasc->filter->name,audiopacket_t.stream_index,audio_st->codec->codec ?  audio_st->codec->codec->name : "copy");                          av_free_packet(&audiopacket_t);                           }                  }              }          }          nRet = av_interleaved_write_frame(oc, &audiopacket_t);          if (nRet != 0)          {              printf("error av_interleaved_write_frame _ audio\n");          }          av_free_packet(&audiopacket_t);      }  }    int Es2Mux_2()  {      for (;;)      {          read_frame(oc);      }      return 1;  }  [cpp] view plain copy //main.cpp  #include "ffmpeg.h"    int main(int argc ,char ** argv)  {      av_register_all();      avformat_network_init();        InitInput(INPUTURL,&icodec,&ifmt);      InitOutput();      printf("--------程序运行开始----------\n");      //////////////////////////////////////////////////////////////////////////      Es2Mux_2();      //////////////////////////////////////////////////////////////////////////      UintOutput();      UintInput();      printf("--------程序运行结束----------\n");      printf("-------请按任意键退出---------\n");      return getchar();  } 

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约