如何为HLS设置ffmpeg选项?

时间:2015-02-18 21:49:53

标签: c++ c ffmpeg

我有一个流媒体设备可以播放视频和音频。我试图捕获这些流并使用ffmpeg的HLS将它们保存为多个.ts文件。

因此,我成功地在单个.ts文件中捕获和保存流。看起来当我将输出文件发送到.m3u8时,ffmpeg会自动选择hls demuxer。但是,这样做我得到一个浮点异常。 这是我的简单代码......

static int ipcam_streaming_main_configure_input_parameters(const char *p_ifilename, AVFormatContext **ppx_ifmt_ctx)

{
   AVStream *px_istream          = NULL;
   AVCodecContext *px_icodec_ctx = NULL;
   int ret                       = -1;
   unsigned int i                = 0;
   enum AVCodecID input_codec_id = AV_CODEC_ID_NONE;
   AVCodec *p_decoder            = NULL;


   if (avformat_open_input(ppx_ifmt_ctx, p_ifilename, NULL, NULL) < 0)

   {
      printf("%s(): avformat_open_input() failed\n", __FUNCTION__);

   }
   else if (avformat_find_stream_info(*ppx_ifmt_ctx, NULL) < 0)
   {
      printf("%s(): avformat_find_stream_info() failed\n", __FUNCTION__);
   }
   else
   {
      /* find the input streams to be remuxed */
      for (i = 0; i < (*ppx_ifmt_ctx)->nb_streams; i++)
      {
         /* get the stream, codec context for the stream */
         px_istream = (*ppx_ifmt_ctx)->streams[i];
         px_icodec_ctx = px_istream->codec;

         if ((AVMEDIA_TYPE_VIDEO == px_icodec_ctx->codec_type)
             || (AVMEDIA_TYPE_AUDIO == px_icodec_ctx->codec_type))
         {
            /* get the codec_id for the audio/video stream */
            input_codec_id = px_icodec_ctx->codec_id;

            /* get the decoder for the input codec id */
            p_decoder = avcodec_find_decoder(px_icodec_ctx->codec_id);

            /* Open decoder for the input codec audio/video */
            ret = avcodec_open2(px_icodec_ctx,
                                p_decoder,
                                NULL);
            if (ret < 0)
            {
               printf("%s(): avcodec_open2() failed\n", __FUNCTION__);
            }
            else
            {
               printf("Input stream type <%d> with codec_id <%d> found and decoder opened\n", px_icodec_ctx->codec_type, input_codec_id);
            }
         }
      }
   }

   /* dump the data into stdout */
   av_dump_format(*ppx_ifmt_ctx, 0, p_ifilename, 0);

   return ret;
}

static int ipcam_streaming_main_configure_output_parameters(const char *p_ofilename,
                                                            AVFormatContext *px_ifmt_ctx,
                                                            AVFormatContext **ppx_ofmt_ctx)
{
   AVStream *px_ostream       = NULL;
   AVStream *px_istream       = NULL;
   AVCodecContext *px_dec_ctx = NULL;
   AVCodecContext *px_enc_ctx = NULL;
   int ret                    = -1;
   unsigned int i             = 0;

   if ((NULL == p_ofilename) || (NULL == px_ifmt_ctx) || (NULL == ppx_ofmt_ctx))
   {
      printf("%s(): NULL arg(s) <%p, %p, %p>", __FUNCTION__, p_ofilename, px_ifmt_ctx, ppx_ofmt_ctx);
      return -1;
   }

   /* remove the output file if already exists */
   remove(p_ofilename);

   /* allocate the output format context */
   if (avformat_alloc_output_context2(ppx_ofmt_ctx, NULL, NULL, p_ofilename) < 0)
   {
      printf("%s(): avformat_alloc_output_context2() failed\n", __FUNCTION__);
   }
   else
   {
      for (i = 0; i < px_ifmt_ctx->nb_streams; i++)
      {
         if ((AVMEDIA_TYPE_VIDEO == px_ifmt_ctx->streams[i]->codec->codec_type)
             || (AVMEDIA_TYPE_AUDIO == px_ifmt_ctx->streams[i]->codec->codec_type))
         {
            printf("Stream <%d> is type <%d>: Adding to output stream\n", i, px_ifmt_ctx->streams[i]->codec->codec_type);

            /* create a new output stream */
            px_ostream = avformat_new_stream(*ppx_ofmt_ctx, NULL);
            if (NULL == px_ostream)
            {
               printf("%s(): avformat_new_stream() failed\n", __FUNCTION__);
            }
            else
            {
               px_istream = px_ifmt_ctx->streams[i];
               px_dec_ctx = px_istream->codec;
               px_enc_ctx = px_ostream->codec;

               /* Since, we do not need to encode the video stream, it is just remuxing
                  just copying the input codec context to output is sufficient */
               ret = avcodec_copy_context((*ppx_ofmt_ctx)->streams[i]->codec,
                                          px_ifmt_ctx->streams[i]->codec);

               if ((*ppx_ofmt_ctx)->oformat->flags & AVFMT_GLOBALHEADER)
               {
                  px_enc_ctx->flags |= CODEC_FLAG_GLOBAL_HEADER;
               }
            }
         }
         else
         {
            printf("Stream <%d> is Unknown: Ignore it \n", i);
         }
      }

      /* dump the output media file into stdout */
      av_dump_format(*ppx_ofmt_ctx, 0, p_ofilename, 1);

      if (0 == ((*ppx_ofmt_ctx)->oformat->flags & AVFMT_NOFILE))
      {
         /* open the output media file so that we can write the data into it */
         ret = avio_open(&(*ppx_ofmt_ctx)->pb, p_ofilename, AVIO_FLAG_WRITE);
         if (ret < 0)
         {
            printf("%s(): avio_open() failed\n", __FUNCTION__);
         }
         else
         {
            /* init muxer, write output file header */
            ret = avformat_write_header((*ppx_ofmt_ctx), NULL);
            if (ret < 0)
            {
               printf("%s(): avformat_write_header() failed\n", __FUNCTION__);
            }
         }
      }
   }

   return ret;
}


int main(int argnum, char **argv)
{
   AVFormatContext *px_ifmt_ctx = NULL;
   AVFormatContext *px_ofmt_ctx = NULL;
   AVPacket packet              = {0};
   enum AVMediaType type        = AVMEDIA_TYPE_UNKNOWN;
   unsigned int stream_index    = -1;
   unsigned int i               = 0;
   int ret                      = -1;

   if (argnum != 3)
   {
      printf("Please enough number of parameters\n");
      return -1;
   }

   /* register all the services requred */
   av_register_all();
   avformat_network_init();

   if (0 != ipcam_streaming_main_configure_input_parameters(argv[1],
                                                            &px_ifmt_ctx))
   {
      printf("%s(): ipcam_streaming_main_configure_iput_parameters() failed\n", __FUNCTION__);
   }
   else if (0 != ipcam_streaming_main_configure_output_parameters(argv[2],
                                                                  px_ifmt_ctx,
                                                                  &px_ofmt_ctx)) 
   {
      printf("%s(): ipcam_streaming_main_configure_output_parameters() failed\n", __FUNCTION__);
   }
   else
   {
      printf("Input and output configuration done successfully: Now reading packets\n");
      while (true)
      {
         if ((ret = av_read_frame(px_ifmt_ctx, &packet)) < 0)
         {
            printf("av_read_frame() failed with error <%d>: Exit\n", ret);
            break;
         }

         /* get the stream index and codec type of the packet read */
         stream_index = packet.stream_index;
         type = px_ifmt_ctx->streams[stream_index]->codec->codec_type;

         /* remux only if the type is video, otherwise ignore it */
         if ((AVMEDIA_TYPE_VIDEO == type)
             || (AVMEDIA_TYPE_AUDIO == type))
         {
            printf("Remuxing the stream type <%d>, frame with stream index <%d>\n", type, stream_index);

            /* remux this frame without reencoding */
            packet.dts = av_rescale_q_rnd(packet.dts,
                                          px_ifmt_ctx->streams[stream_index]->time_base,
                                          px_ofmt_ctx->streams[stream_index]->time_base,
                                          AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX);

            packet.pts = av_rescale_q_rnd(packet.pts,
                                          px_ifmt_ctx->streams[stream_index]->time_base,
                                          px_ofmt_ctx->streams[stream_index]->time_base,
                                          AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX);

            /* write the frame into the output media file */
            ret = av_write_frame(px_ofmt_ctx, &packet);

            if (ret < 0)
            {
               printf("Ignoring video packet stream index <%d>\n", packet.stream_index);
            }

            /* free the packet for next use */
            av_free_packet(&packet);
         }
         else
         {
            printf("Ignoring stream index <%d>, type <%d>\n", packet.stream_index, type);
         }
      }
   }

   /* write the trailer */
   av_write_trailer(px_ofmt_ctx);

   av_free_packet(&packet);

   for (i = 0; i < px_ifmt_ctx->nb_streams; i++)
   {
      /* close the input codec that has been opened */
      avcodec_close(px_ifmt_ctx->streams[i]->codec);

      if ((NULL != px_ofmt_ctx) && (px_ofmt_ctx->nb_streams > i) && 
          (NULL != px_ofmt_ctx->streams[i]) && ( NULL != px_ofmt_ctx->streams[i]->codec))
      {
         /* close the output code */
         avcodec_close(px_ofmt_ctx->streams[i]->codec);
      }
   }

   /* close the input */
   avformat_close_input(&px_ifmt_ctx);

   if ((NULL != px_ofmt_ctx) && (0 == (px_ofmt_ctx->oformat->flags & AVFMT_NOFILE)))
   {
      /* close the output context */
      avio_close(px_ofmt_ctx->pb);
   }

   /* free the output context */
   avformat_free_context(px_ofmt_ctx);

   return ret;
}

因此,如果我将输出文件名传递给.m3u8文件,则会产生浮点异常。

0 个答案:

没有答案