ffmpeg文件生成m3u8文件及ts切片程序(一)

24 篇文章 2 订阅
13 篇文章 0 订阅

转载: http://blog.csdn.net/zhuweigangzwg/article/details/50837005    谢谢原作者

实现目标:输入本地文件,实现m3u8切片,功能点请看注释,注意:注释很重要。

参考:

http://www.cnblogs.com/mystory/archive/2013/04/07/3006200.html

https://github.com/johnf/m3u8-segmenter/pull/10/files#diff-e1c7f1b21ff66b32c10d790c3855aedeR42

https://github.com/johnf/m3u8-segmenter

 

[cpp] view plain copy  在CODE上查看代码片派生到我的代码片

  1. //ffmpeg.h  
  2. #ifndef __FFMPEG_H__  
  3. #define __FFMPEG_H__  
  4.   
  5. #include "info.h"  
  6.   
  7. extern "C"  
  8. {  
  9. #include "libavformat/avformat.h"  
  10. #include "libavformat/avio.h"  
  11. #include "libavcodec/avcodec.h"  
  12. #include "libswscale/swscale.h"  
  13. #include "libavutil/avutil.h"  
  14. #include "libavutil/mathematics.h"  
  15. #include "libswresample/swresample.h"  
  16. #include "libavutil/opt.h"  
  17. #include "libavutil/channel_layout.h"  
  18. #include "libavutil/samplefmt.h"  
  19. #include "libavdevice/avdevice.h"  //摄像头所用  
  20. #include "libavfilter/avfilter.h"  
  21. #include "libavutil/error.h"  
  22. #include "libavutil/mathematics.h"    
  23. #include "libavutil/time.h"    
  24. #include "libavutil/fifo.h"  
  25. #include "libavutil/audio_fifo.h"   //这里是做分片时候重采样编码音频用的  
  26. #include "inttypes.h"  
  27. #include "stdint.h"  
  28. };  
  29.   
  30. #pragma comment(lib,"avformat.lib")  
  31. #pragma comment(lib,"avcodec.lib")  
  32. #pragma comment(lib,"avdevice.lib")  
  33. #pragma comment(lib,"avfilter.lib")  
  34. #pragma comment(lib,"avutil.lib")  
  35. #pragma comment(lib,"postproc.lib")  
  36. #pragma comment(lib,"swresample.lib")  
  37. #pragma comment(lib,"swscale.lib")  
  38.   
  39. #define AUDIO_ID            0    //packet 中的ID ,如果先加入音频 pocket 则音频是 0  视频是1,否则相反(影响add_out_stream顺序)  
  40. #define VIDEO_ID            1  
  41.   
  42. //#define INPUTURL   "../in_stream/22.ts"  
  43. #define INPUTURL   "../in_stream/avier1.mp4"      
  44. //#define INPUTURL   "../in_stream/father.avi"    //这个有问题?没有音频  
  45. //#define INPUTURL   "../in_stream/ceshi.avi"   
  46.   
  47. //m3u8 param  
  48. #define OUTPUT_PREFIX       "ZWG_TEST"              //切割文件的前缀  
  49. #define M3U8_FILE_NAME      "ZWG_TEST.m3u8"         //生成的m3u8文件名  
  50. #define URL_PREFIX          "../out_stream/"        //生成目录  
  51. #define NUM_SEGMENTS        50                      //在磁盘上一共最多存储多少个分片  
  52. #define SEGMENT_DURATION    10                      //每一片切割多少秒  
  53. extern unsigned int m_output_index;                 //生成的切片文件顺序编号(第几个文件)  
  54. extern char m_output_file_name[256];                //输入的要切片的文件  
  55.   
  56.   
  57. extern int nRet;                                                              //状态标志  
  58. extern AVFormatContext* icodec;                                               //输入流context  
  59. extern AVFormatContext* ocodec ;                                              //输出流context  
  60. extern char szError[256];                                                     //错误字符串  
  61. extern AVStream* ovideo_st;  
  62. extern AVStream* oaudio_st;                
  63. extern int video_stream_idx;  
  64. extern int audio_stream_idx;  
  65. extern AVCodec *audio_codec;  
  66. extern AVCodec *video_codec;     
  67. extern AVBitStreamFilterContext * vbsf_aac_adtstoasc;                         //aac->adts to asc过滤器  
  68. static struct SwsContext * img_convert_ctx_video = NULL;  
  69. static int sws_flags = SWS_BICUBIC; //差值算法,双三次  
  70. extern AVBitStreamFilterContext * vbsf_h264_toannexb;  
  71. extern int IsAACCodes;  
  72.   
  73. int init_demux(char * Filename,AVFormatContext ** iframe_c);  
  74. int init_mux();  
  75. int uinit_demux();  
  76. int uinit_mux();  
  77. //for mux  
  78. AVStream * add_out_stream(AVFormatContext* output_format_context,AVMediaType codec_type_t);   
  79.   
  80. //具体的切片程序  
  81. void slice_up();  
  82. //填写m3u8文件  
  83. int write_index_file(const unsigned int first_segment, const unsigned int last_segment, const int end, const unsigned int actual_segment_durations[]);  
  84.   
  85.   
  86. #endif  

 

[cpp] view plain copy  在CODE上查看代码片派生到我的代码片

  1. //ffmpeg.cpp  
  2. #include "ffmpeg.h"  
  3.   
  4. int nRet = 0;  
  5. AVFormatContext* icodec = NULL;   
  6. AVFormatContext* ocodec = NULL;  
  7. char szError[256];   
  8. AVStream * ovideo_st = NULL;  
  9. AVStream * oaudio_st = NULL;  
  10. int video_stream_idx = -1;  
  11. int audio_stream_idx = -1;  
  12. AVCodec *audio_codec = NULL;  
  13. AVCodec *video_codec = NULL;  
  14. AVBitStreamFilterContext * vbsf_aac_adtstoasc = NULL;  
  15. AVBitStreamFilterContext * vbsf_h264_toannexb = NULL;  
  16. int IsAACCodes = 0;  
  17.   
  18. //m3u8 param  
  19. unsigned int m_output_index = 1;       //生成的切片文件顺序编号  
  20. char m_output_file_name[256];          //输入的要切片的文件  
  21.   
  22. int init_demux(char * Filename,AVFormatContext ** iframe_c)  
  23. {  
  24.     int i = 0;  
  25.     nRet = avformat_open_input(iframe_c, Filename,NULL, NULL);  
  26.     if (nRet != 0)  
  27.     {  
  28.         av_strerror(nRet, szError, 256);  
  29.         printf(szError);  
  30.         printf("\n");  
  31.         printf("Call avformat_open_input function failed!\n");  
  32.         return 0;  
  33.     }  
  34.     if (avformat_find_stream_info(*iframe_c,NULL) < 0)  
  35.     {  
  36.         printf("Call av_find_stream_info function failed!\n");  
  37.         return 0;  
  38.     }  
  39.     //输出视频信息  
  40.     av_dump_format(*iframe_c, -1, Filename, 0);  
  41.   
  42.     //添加音频信息到输出context  
  43.     for (i = 0; i < (*iframe_c)->nb_streams; i++)  
  44.     {  
  45.         if ((*iframe_c)->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)  
  46.         {  
  47.             video_stream_idx = i;  
  48.         }  
  49.         else if ((*iframe_c)->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO)  
  50.         {  
  51.             audio_stream_idx = i;  
  52.         }  
  53.     }  
  54.   
  55.     if ((strstr(icodec->iformat->name, "flv") != NULL) ||   
  56.         (strstr(icodec->iformat->name, "mp4") != NULL) ||   
  57.         (strstr(icodec->iformat->name, "mov") != NULL))      
  58.     {  
  59.         if (icodec->streams[video_stream_idx]->codec->codec_id == AV_CODEC_ID_H264)  //AV_CODEC_ID_H264  
  60.         {  
  61.             //这里注意:"h264_mp4toannexb",一定是这个字符串,无论是 flv,mp4,mov格式  
  62.             vbsf_h264_toannexb = av_bitstream_filter_init("h264_mp4toannexb");   
  63.         }   
  64.         if (icodec->streams[audio_stream_idx]->codec->codec_id == AV_CODEC_ID_AAC) //AV_CODEC_ID_AAC  
  65.         {  
  66.             IsAACCodes = 1;  
  67.         }  
  68.     }   
  69.   
  70.     return 1;  
  71. }  
  72.   
  73. int init_mux()  
  74. {  
  75.     int ret = 0;  
  76.     /* allocate the output media context */  
  77.     avformat_alloc_output_context2(&ocodec, NULL,NULL, m_output_file_name);  
  78.     if (!ocodec)   
  79.     {  
  80.         return getchar();  
  81.     }  
  82.     AVOutputFormat* ofmt = NULL;  
  83.     ofmt = ocodec->oformat;  
  84.   
  85.     /* open the output file, if needed */  
  86.     if (!(ofmt->flags & AVFMT_NOFILE))  
  87.     {  
  88.         if (avio_open(&ocodec->pb, m_output_file_name, AVIO_FLAG_WRITE) < 0)  
  89.         {  
  90.             printf("Could not open '%s'\n", m_output_file_name);  
  91.             return getchar();  
  92.         }  
  93.     }  
  94.   
  95.     //这里添加的时候AUDIO_ID/VIDEO_ID有影响  
  96.     //添加音频信息到输出context  
  97.     if(audio_stream_idx != -1)//如果存在音频  
  98.     {  
  99.         oaudio_st = add_out_stream(ocodec, AVMEDIA_TYPE_AUDIO);  
  100.     }  
  101.   
  102.     //添加视频信息到输出context  
  103.     if (video_stream_idx != -1)//如果存在视频  
  104.     {  
  105.         ovideo_st = add_out_stream(ocodec,AVMEDIA_TYPE_VIDEO);  
  106.     }  
  107.   
  108.     av_dump_format(ocodec, 0, m_output_file_name, 1);  
  109.   
  110.     ret = avformat_write_header(ocodec, NULL);  
  111.     if (ret != 0)  
  112.     {  
  113.         printf("Call avformat_write_header function failed.\n");  
  114.         return 0;  
  115.     }  
  116.     return 1;  
  117. }  
  118.   
  119. int uinit_demux()  
  120. {  
  121.     /* free the stream */  
  122.     av_free(icodec);  
  123.     if (vbsf_h264_toannexb !=NULL)  
  124.     {  
  125.         av_bitstream_filter_close(vbsf_h264_toannexb);  
  126.         vbsf_h264_toannexb = NULL;  
  127.     }  
  128.     return 1;  
  129. }  
  130.   
  131. int uinit_mux()  
  132. {  
  133.     int i = 0;  
  134.     nRet = av_write_trailer(ocodec);  
  135.     if (nRet < 0)  
  136.     {  
  137.         av_strerror(nRet, szError, 256);  
  138.         printf(szError);  
  139.         printf("\n");  
  140.         printf("Call av_write_trailer function failed\n");  
  141.     }  
  142.     if (vbsf_aac_adtstoasc !=NULL)  
  143.     {  
  144.         av_bitstream_filter_close(vbsf_aac_adtstoasc);   
  145.         vbsf_aac_adtstoasc = NULL;  
  146.     }  
  147.   
  148.     /* Free the streams. */  
  149.     for (i = 0; i < ocodec->nb_streams; i++)   
  150.     {  
  151.         av_freep(&ocodec->streams[i]->codec);  
  152.         av_freep(&ocodec->streams[i]);  
  153.     }  
  154.     if (!(ocodec->oformat->flags & AVFMT_NOFILE))  
  155.     {  
  156.         /* Close the output file. */  
  157.         avio_close(ocodec->pb);  
  158.     }  
  159.     av_free(ocodec);  
  160.     return 1;  
  161. }  
  162.   
  163. AVStream * add_out_stream(AVFormatContext* output_format_context,AVMediaType codec_type_t)  
  164. {  
  165.     AVStream * in_stream = NULL;  
  166.     AVStream * output_stream = NULL;  
  167.     AVCodecContext* output_codec_context = NULL;  
  168.   
  169.     output_stream = avformat_new_stream(output_format_context,NULL);  
  170.     if (!output_stream)  
  171.     {  
  172.         return NULL;  
  173.     }  
  174.   
  175.     switch (codec_type_t)  
  176.     {  
  177.     case AVMEDIA_TYPE_AUDIO:  
  178.         in_stream = icodec->streams[audio_stream_idx];  
  179.         break;  
  180.     case AVMEDIA_TYPE_VIDEO:  
  181.         in_stream = icodec->streams[video_stream_idx];  
  182.         break;  
  183.     default:  
  184.         break;  
  185.     }  
  186.   
  187.     output_stream->id = output_format_context->nb_streams - 1;  
  188.     output_codec_context = output_stream->codec;  
  189.     output_stream->time_base  = in_stream->time_base;  
  190.   
  191.     int ret = 0;  
  192.     ret = avcodec_copy_context(output_stream->codec, in_stream->codec);  
  193.     if (ret < 0)   
  194.     {  
  195.         printf("Failed to copy context from input to output stream codec context\n");  
  196.         return NULL;  
  197.     }  
  198.   
  199.     //这个很重要,要么纯复用解复用,不做编解码写头会失败,  
  200.     //另或者需要编解码如果不这样,生成的文件没有预览图,还有添加下面的header失败,置0之后会重新生成extradata  
  201.     output_codec_context->codec_tag = 0;   
  202.   
  203.     //if(! strcmp( output_format_context-> oformat-> name,  "mp4" ) ||  
  204.     //!strcmp (output_format_context ->oformat ->name , "mov" ) ||  
  205.     //!strcmp (output_format_context ->oformat ->name , "3gp" ) ||  
  206.     //!strcmp (output_format_context ->oformat ->name , "flv"))  
  207.     if(AVFMT_GLOBALHEADER & output_format_context->oformat->flags)  
  208.     {  
  209.         output_codec_context->flags |= CODEC_FLAG_GLOBAL_HEADER;  
  210.     }  
  211.     return output_stream;  
  212. }  
  213.   
  214. int write_index_file(const unsigned int first_segment, const unsigned int last_segment, const int end, const unsigned int actual_segment_durations[])  
  215. {  
  216.     FILE *index_fp = NULL;  
  217.     char *write_buf = NULL;  
  218.     unsigned int i = 0;  
  219.     char m3u8_file_pathname[256] = {0};  
  220.   
  221.     sprintf(m3u8_file_pathname,"%s%s",URL_PREFIX,M3U8_FILE_NAME);  
  222.       
  223.     index_fp = fopen(m3u8_file_pathname,"w");  
  224.     if (!index_fp)  
  225.     {  
  226.         printf("Could not open m3u8 index file (%s), no index file will be created\n",(char *)m3u8_file_pathname);  
  227.         return -1;  
  228.     }  
  229.   
  230.     write_buf = (char *)malloc(sizeof(char) * 1024);  
  231.     if (!write_buf)   
  232.     {  
  233.         printf("Could not allocate write buffer for index file, index file will be invalid\n");  
  234.         fclose(index_fp);  
  235.         return -1;  
  236.     }  
  237.   
  238.   
  239.     if (NUM_SEGMENTS)  
  240.     {  
  241.         //#EXT-X-MEDIA-SEQUENCE:<Number> 播放列表文件中每个媒体文件的URI都有一个唯一的序列号。URI的序列号等于它之前那个RUI的序列号加一(没有填0)  
  242.         sprintf(write_buf,"#EXTM3U\n#EXT-X-TARGETDURATION:%lu\n#EXT-X-MEDIA-SEQUENCE:%u\n",SEGMENT_DURATION,first_segment);  
  243.     }  
  244.     else   
  245.     {  
  246.         sprintf(write_buf,"#EXTM3U\n#EXT-X-TARGETDURATION:%lu\n",SEGMENT_DURATION);  
  247.     }  
  248.     if (fwrite(write_buf, strlen(write_buf), 1, index_fp) != 1)   
  249.     {  
  250.         printf("Could not write to m3u8 index file, will not continue writing to index file\n");  
  251.         free(write_buf);  
  252.         fclose(index_fp);  
  253.         return -1;  
  254.     }  
  255.   
  256.     for (i = first_segment; i <= last_segment; i++)   
  257.     {  
  258.         sprintf(write_buf,"#EXTINF:%u,\n%s%s-%u.ts\n",actual_segment_durations[i-1],URL_PREFIX,OUTPUT_PREFIX,i);  
  259.         if (fwrite(write_buf, strlen(write_buf), 1, index_fp) != 1)   
  260.         {  
  261.             printf("Could not write to m3u8 index file, will not continue writing to index file\n");  
  262.             free(write_buf);  
  263.             fclose(index_fp);  
  264.             return -1;  
  265.         }  
  266.     }  
  267.   
  268.     if (end)   
  269.     {  
  270.         sprintf(write_buf,"#EXT-X-ENDLIST\n");  
  271.         if (fwrite(write_buf, strlen(write_buf), 1, index_fp) != 1)  
  272.         {  
  273.             printf("Could not write last file and endlist tag to m3u8 index file\n");  
  274.             free(write_buf);  
  275.             fclose(index_fp);  
  276.             return -1;  
  277.         }  
  278.     }  
  279.   
  280.     free(write_buf);  
  281.     fclose(index_fp);  
  282.     return 0;  
  283. }  
  284.   
  285. void slice_up()  
  286. {  
  287.     int write_index = 1;  
  288.     unsigned int first_segment = 1;     //第一个分片的标号  
  289.     unsigned int last_segment = 0;      //最后一个分片标号  
  290.     int decode_done = 0;                //文件是否读取完成  
  291.     int remove_file = 0;                //是否要移除文件(写在磁盘的分片已经达到最大)  
  292.     char remove_filename[256] = {0};    //要从磁盘上删除的文件名称  
  293.     double prev_segment_time = 0;       //上一个分片时间  
  294.     int ret = 0;  
  295.     unsigned int actual_segment_durations[1024] = {0}; //各个分片文件实际的长度  
  296.   
  297.     //填写第一个输出文件名称  
  298.     sprintf(m_output_file_name,"%s%s-%u.ts",URL_PREFIX,OUTPUT_PREFIX,m_output_index ++);  
  299.   
  300.     //****************************************创建输出文件(写头部)  
  301.     init_mux();  
  302.   
  303.     write_index = !write_index_file(first_segment, last_segment, 0, actual_segment_durations);  
  304.   
  305.     do   
  306.     {  
  307.         unsigned int current_segment_duration;  
  308.         double segment_time = prev_segment_time;  
  309.         AVPacket packet;  
  310.         av_init_packet(&packet);  
  311.   
  312.         decode_done = av_read_frame(icodec, &packet);  
  313.         if (decode_done < 0)   
  314.         {  
  315.             break;  
  316.         }  
  317.   
  318.         if (av_dup_packet(&packet) < 0)   
  319.         {  
  320.             printf("Could not duplicate packet");  
  321.             av_free_packet(&packet);  
  322.             break;  
  323.         }  
  324.   
  325.         if (packet.stream_index == video_stream_idx )   
  326.         {  
  327.             segment_time = packet.pts * av_q2d(icodec->streams[video_stream_idx]->time_base);  
  328.         }  
  329.         else if (video_stream_idx < 0)   
  330.         {  
  331.             segment_time = packet.pts * av_q2d(icodec->streams[audio_stream_idx]->time_base);  
  332.         }  
  333.         else   
  334.         {  
  335.             segment_time = prev_segment_time;  
  336.         }  
  337.   
  338.         //这里是为了纠错,有文件pts为不可用值  
  339.         if (packet.pts < packet.dts)  
  340.         {  
  341.             packet.pts = packet.dts;  
  342.         }  
  343.   
  344.         //视频  
  345.         if (packet.stream_index == video_stream_idx )   
  346.         {  
  347.             if (vbsf_h264_toannexb != NULL)  
  348.             {  
  349.                 AVPacket filteredPacket = packet;   
  350.                 int a = av_bitstream_filter_filter(vbsf_h264_toannexb,                                             
  351.                     ovideo_st->codec, NULL,&filteredPacket.data, &filteredPacket.size, packet.data, packet.size, packet.flags & AV_PKT_FLAG_KEY);   
  352.                 if (a > 0)               
  353.                 {                  
  354.                     av_free_packet(&packet);   
  355.                     packet.pts = filteredPacket.pts;  
  356.                     packet.dts = filteredPacket.dts;  
  357.                     packet.duration = filteredPacket.duration;  
  358.                     packet.flags = filteredPacket.flags;  
  359.                     packet.stream_index = filteredPacket.stream_index;  
  360.                     packet.data = filteredPacket.data;    
  361.                     packet.size = filteredPacket.size;          
  362.                 }               
  363.                 else if (a < 0)              
  364.                 {                  
  365.                     fprintf(stderr, "%s failed for stream %d, codec %s",  
  366.                         vbsf_h264_toannexb->filter->name,packet.stream_index,ovideo_st->codec->codec ?  ovideo_st->codec->codec->name : "copy");  
  367.                     av_free_packet(&packet);                  
  368.                     getchar();             
  369.                 }  
  370.             }  
  371.   
  372.             packet.pts = av_rescale_q_rnd(packet.pts, icodec->streams[video_stream_idx]->time_base, ovideo_st->time_base, AV_ROUND_NEAR_INF);  
  373.             packet.dts = av_rescale_q_rnd(packet.dts, icodec->streams[video_stream_idx]->time_base, ovideo_st->time_base, AV_ROUND_NEAR_INF);  
  374.             packet.duration = av_rescale_q(packet.duration,icodec->streams[video_stream_idx]->time_base, ovideo_st->time_base);  
  375.   
  376.             packet.stream_index = VIDEO_ID; //这里add_out_stream顺序有影响  
  377.             printf("video\n");  
  378.         }  
  379.         else if (packet.stream_index == audio_stream_idx)  
  380.         {  
  381.             packet.pts = av_rescale_q_rnd(packet.pts, icodec->streams[audio_stream_idx]->time_base, oaudio_st->time_base, AV_ROUND_NEAR_INF);  
  382.             packet.dts = av_rescale_q_rnd(packet.dts, icodec->streams[audio_stream_idx]->time_base, oaudio_st->time_base, AV_ROUND_NEAR_INF);  
  383.             packet.duration = av_rescale_q(packet.duration,icodec->streams[audio_stream_idx]->time_base, oaudio_st->time_base);  
  384.   
  385.             packet.stream_index = AUDIO_ID; //这里add_out_stream顺序有影响  
  386.             printf("audio\n");  
  387.         }  
  388.   
  389.         current_segment_duration = (int)(segment_time - prev_segment_time + 0.5);  
  390.         actual_segment_durations[last_segment] = (current_segment_duration > 0 ? current_segment_duration: 1);  
  391.   
  392.         if (segment_time - prev_segment_time >= SEGMENT_DURATION)   
  393.         {  
  394.             ret = av_write_trailer(ocodec);   // close ts file and free memory  
  395.             if (ret < 0)   
  396.             {  
  397.                 printf("Warning: Could not av_write_trailer of stream\n");  
  398.             }  
  399.   
  400.             avio_flush(ocodec->pb);  
  401.             avio_close(ocodec->pb);  
  402.   
  403.             if (NUM_SEGMENTS && (int)(last_segment - first_segment) >= NUM_SEGMENTS - 1)  
  404.             {  
  405.                 remove_file = 1;  
  406.                 first_segment++;  
  407.             }  
  408.             else   
  409.             {  
  410.                 remove_file = 0;  
  411.             }  
  412.   
  413.             if (write_index)   
  414.             {  
  415.                 write_index = !write_index_file(first_segment, ++last_segment, 0,actual_segment_durations);  
  416.             }  
  417.   
  418.             if (remove_file)   
  419.             {  
  420.                 sprintf(remove_filename,"%s%s-%u.ts",URL_PREFIX,OUTPUT_PREFIX,first_segment - 1);  
  421.                 remove(remove_filename);  
  422.             }  
  423.   
  424.             sprintf(m_output_file_name,"%s%s-%u.ts",URL_PREFIX,OUTPUT_PREFIX,m_output_index ++);  
  425.             if (avio_open(&ocodec->pb, m_output_file_name, AVIO_FLAG_WRITE) < 0)  
  426.             {  
  427.                 printf("Could not open '%s'\n", m_output_file_name);  
  428.                 break;  
  429.             }  
  430.   
  431.             // Write a new header at the start of each file  
  432.             if (avformat_write_header(ocodec, NULL))  
  433.             {  
  434.                 printf("Could not write mpegts header to first output file\n");  
  435.                 exit(1);  
  436.             }  
  437.   
  438.             prev_segment_time = segment_time;  
  439.         }  
  440.   
  441.         ret = av_interleaved_write_frame(ocodec, &packet);  
  442.         if (ret < 0)   
  443.         {  
  444.             printf("Warning: Could not write frame of stream\n");  
  445.         }  
  446.         else if (ret > 0)   
  447.         {  
  448.             printf("End of stream requested\n");  
  449.             av_free_packet(&packet);  
  450.             break;  
  451.         }  
  452.   
  453.         av_free_packet(&packet);  
  454.     } while (!decode_done);  
  455.   
  456.     //****************************************完成输出文件(写尾部)  
  457.     uinit_mux();  
  458.   
  459.     if (NUM_SEGMENTS && (int)(last_segment - first_segment) >= NUM_SEGMENTS - 1)  
  460.     {  
  461.         remove_file = 1;  
  462.         first_segment++;  
  463.     }  
  464.     else   
  465.     {  
  466.         remove_file = 0;  
  467.     }  
  468.   
  469.     if (write_index)   
  470.     {  
  471.         write_index_file(first_segment, ++last_segment, 1, actual_segment_durations);  
  472.     }  
  473.   
  474.     if (remove_file)  
  475.     {  
  476.         sprintf(remove_filename,"%s%s-%u.ts",URL_PREFIX,OUTPUT_PREFIX,first_segment - 1);  
  477.         remove(remove_filename);  
  478.     }  
  479.   
  480.     return;  
  481. }  


实现效果:

 

 

源码地址:http://download.csdn.net/detail/zhuweigangzwg/9456780

 

交流请加QQ群:62054820
QQ:379969650.

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值