Generate an m3u8 file and a TS slicing program using the FFMPEG file (I)
Purpose: enter a local file to implement m3u8 slicing. For more information about the function, see notes. Note: notes are important.
Refer:
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
// 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" // used by the camera
# Include "libavfilter/avfilter. H"
# Include "libavutil/error. H"
# Include "libavutil/mathematics. H"
# Include "libavutil/time. H"
# Include "libavutil/FIFO. H"
# Include "libavutil/audio_polico.h" // This is used for re-sampling and encoding audio during multipart processing.
# 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 audio_id 0 // ID in packet. if you add the audio pocket first, the audio is 0, and the video is 1; otherwise, the opposite is true (affecting the add_out_stream sequence)
# Define video_id 1
// # Define inputurl "../in_stream/22.ts"
# Define inputurl "../in_stream/avier1.mp4"
/// # Define inputurl "../in_stream/father. Avi" // is there a problem? No audio
// # Define inputurl "../in_stream/Ceshi. Avi"
// M3u8 Param
# Define output_prefix "zwg_test" // prefix of the cut File
# Define m3u8_file_name "zwg_test.m3u8" // generated m3u8 file name
# Define url_prefix "../out_stream/" // generate a directory
# Define num_segments 50 // maximum number of partitions stored on the disk
# Define segment_duration 10 // The number of seconds each piece is cut
Extern unsigned int m_output_index; // The sequential number of the generated slice file (number of the files)
Extern char m_output_file_name [256]; // input the file to be sliced
Extern int nret; // status flag
Extern avformatcontext * icodec; // input stream Context
Extern avformatcontext * ocodec; // output stream Context
Extern char szerror [256]; // error string
Extern avstream * ovideo_st;
Extern avstream * oaudio_st;
Extern int video_stream_idx;
Extern int audio_stream_idx;
Extern avcodec * audio_codec;
Extern avcodec * video_codec;
Extern avbitstreamfiltercontext * vbsf_aac_adtstoasc; // AAC-> ADTs to ASC Filter
Static struct swscontext * img_convert_ctx_video = NULL;
Static int sws_flags = sws_bicubic; // difference algorithm, double three times
Extern avbitstreamfiltercontext * vbsf_h1__to1_ B;
Extern int isaaccodes;
Int init_demux (char * filename, avformatcontext ** iframe_c );
Int init_mux ();
Int uinit_demux ();
Int uinit_mux ();
// For MUX
Avstream * add_out_stream (avformatcontext * output_format_context, avmediatype codec_type_t );
// Specific slicing Program
Void slice_up ();
// Fill in the m3u8 File
Int write_index_file (const unsigned int first_segment, const unsigned int last_segment, const int end, const unsigned int actual_segment_durations []);
# Endif
// FFMPEG. cpp
# Include "FFMPEG. H"
Int nret = 0;
Avformatcontext * icodec = NULL;
Avformatcontext * ocodec = NULL;
Char szerror [256];
Avstream * ovideo_st = NULL;
Avstream * oaudio_st = NULL;
Int video_stream_idx =-1;
Int audio_stream_idx =-1;
Avcodec * audio_codec = NULL;
Avcodec * video_codec = NULL;
Avbitstreamfiltercontext * vbsf_aac_adtstoasc = NULL;
Avbitstreamfiltercontext * vbsf_h1__to1_ B = NULL;
Int isaaccodes = 0;
// M3u8 Param
Unsigned int m_output_index = 1; // sequential number of the generated slice File
Char m_output_file_name [256]; // input the file to be sliced
Int init_demux (char * filename, avformatcontext ** iframe_c)
{
Int I = 0;
Nret = avformat_open_input (iframe_c, filename, null, null );
If (nret! = 0)
{
Av_strerror (nret, szerror, 256 );
Printf (szerror );
Printf ("\ n ");
Printf ("Call avformat_open_input function failed! \ N ");
Return 0;
}
If (avformat_find_stream_info (* iframe_c, null) <0)
{
Printf ("Call av_find_stream_info function failed! \ N ");
Return 0;
}
// Output video information
Av_dump_format (* iframe_c,-1, filename, 0 );
// Add Audio Information to the output 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;
}
Else if (* iframe_c)-> streams [I]-> codec-> codec_type = avmedia_type_audio)
{
Audio_stream_idx = I;
}
}
If (strstr (icodec-> iformat-> name, "FLV ")! = NULL) |
(Strstr (icodec-> iformat-> name, "MP4 ")! = NULL) |
(Strstr (icodec-> iformat-> name, "mov ")! = NULL ))
{
If (icodec-> streams [video_stream_idx]-> codec-> codec_id = av_codec_id_h264) // av_codec_id_h264
{
// Note: "h1__mp4to1_ B" must be this string, in FLV, MP4, and mov formats.
Vbsf_h1__to1_ B = av_bitstream_filter_init ("h1__mp4to1_ B ");
}
If (icodec-> streams [audio_stream_idx]-> codec-> codec_id = av_codec_id_aac) // av_codec_id_aac
{
Isaaccodes = 1;
}
}
Return 1;
}
Int init_mux ()
{
Int ret = 0;
/* Allocate the output media context */
Avformat_alloc_output_context2 (& ocodec, null, null, m_output_file_name );
If (! Ocodec)
{
Return getchar ();
}
Avoutputformat * ofmt = NULL;
Ofmt = ocodec-> oformat;
/* Open the output file, if needed */
If (! (Ofmt-> flags & avfmt_nofile ))
{
If (avio_open (& ocodec-> Pb, m_output_file_name, avio_flag_write) <0)
{
Printf ("cocould not open '% s' \ n", m_output_file_name );
Return getchar ();
}
}
// Audio_id/video_id is affected when you add it here.
// Add Audio Information to the output Context
If (audio_stream_idx! =-1) // If audio exists
{
Oaudio_st = add_out_stream (ocodec, avmedia_type_audio );
}
// Add the video information to the output Context
If (video_stream_idx! =-1) // If a video exists
{
Ovideo_st = add_out_stream (ocodec, avmedia_type_video );
}
Av_dump_format (ocodec, 0, m_output_file_name, 1 );
Ret = avformat_write_header (ocodec, null );
If (Ret! = 0)
{
Printf ("Call avformat_write_header function failed. \ n ");
Return 0;
}
Return 1;
}
Int uinit_demux ()
{
/* Free the stream */
Av_free (icodec );
If (vbsf_h1__to1_ B! = NULL)
{
Av_bitstream_filter_close (vbsf_h1__to1_ B );
Vbsf_h1__to1_ B = NULL;
}
Return 1;
}
Int uinit_mux ()
{
Int I = 0;
Nret = av_write_trailer (ocodec );
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;
}
/* Free the streams .*/
For (I = 0; I <ocodec-> nb_streams; I ++)
{
Av_freep (& ocodec-> streams [I]-> codec );
Av_freep (& ocodec-> streams [I]);
}
If (! (Ocodec-> oformat-> flags & avfmt_nofile ))
{
/* Close the output file .*/
Avio_close (ocodec-> Pb );
}
Av_free (ocodec );
Return 1;
}
Avstream * add_out_stream (avformatcontext * output_format_context, avmediatype codec_type_t)
{
Avstream * in_stream = NULL;
Avstream * output_stream = NULL;
Avcodeccontext * output_codec_context = NULL;
Output_stream = avformat_new_stream (output_format_context, null );
If (! Output_stream)
{
Return NULL;
}
Switch (codec_type_t)
{
Case avmedia_type_audio:
In_stream = icodec-> streams [audio_stream_idx];
Break;
Case avmedia_type_video:
In_stream = icodec-> streams [video_stream_idx];
Break;
Default:
Break;
}
Output_stream-> id = output_format_context-> nb_streams-1;
Output_codec_context = output_stream-> codec;
Output_stream-> time_base = in_stream-> time_base;
Int ret = 0;
Ret = avcodec_copy_context (output_stream-> codec, in_stream-> codec );
If (Ret <0)
{
Printf ("failed to copy context from input to output stream codec context \ n ");
Return NULL;
}
// This is very important. Either it is purely reusable and demultiplexing. Failure will occur if no encoding/decoding header is used,
// Alternatively, if the encoding/decoding method is not used, the generated file does not have a preview image, and the following header fails to be added. After the value is set to 0, the extradata is regenerated.
Output_codec_context-> codec_tag = 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 "))
If (avfmt_globalheader & output_format_context-> oformat-> flags)
{
Output_codec_context-> flags | = codec_flag_global_header;
}
Return output_stream;
}
Int write_index_file (const unsigned int first_segment, const unsigned int last_segment, const int end, const unsigned int actual_segment_durations [])
{
File * index_fp = NULL;
Char * write_buf = NULL;
Unsigned int I = 0;
Char m3u8_file_pathname [1, 256] = {0 };
Sprintf (m3u8_file_pathname, "% S % s", url_prefix, m3u8_file_name );
Index_fp = fopen (m3u8_file_pathname, "W ");
If (! Index_fp)
{
Printf ("cocould not open m3u8 index file (% s), no index file will be created \ n", (char *) m3u8_file_pathname );
Return-1;
}
Write_buf = (char *) malloc (sizeof (char) * 1024 );
If (! Write_buf)
{
Printf ("cocould not allocate write buffer for index file, index file will be invalid \ n ");
Fclose (index_fp );
Return-1;
}
If (num_segments)
{
// # EXT-X-MEDIA-SEQUENCE: The URI of each media file in the playlist file has a unique serial number. The serial number of URI is equal to the serial number of the previous Rui plus one (0 is not entered)
Sprintf (write_buf, "# extm3u \ n # EXT-X-TARGETDURATION: % lu \ n # EXT-X-MEDIA-SEQUENCE: % u \ n", segment_duration, first_segment );
}
Else
{
Sprintf (write_buf, "# extm3u \ n # EXT-X-TARGETDURATION: % lu \ n", segment_duration );
}
If (fwrite (write_buf, strlen (write_buf), 1, index_fp )! = 1)
{
Printf ("cocould not write to m3u8 index file, will not continue writing to index file \ n ");
Free (write_buf );
Fclose (index_fp );
Return-1;
}
For (I = first_segment; I <= last_segment; I ++)
{
Sprintf (write_buf, "# extinf: % u, \ n % S % s-% u. Ts \ n", actual_segment_durations [I-1], url_prefix, output_prefix, I );
If (fwrite (write_buf, strlen (write_buf), 1, index_fp )! = 1)
{
Printf ("cocould not write to m3u8 index file, will not continue writing to index file \ n ");
Free (write_buf );
Fclose (index_fp );
Return-1;
}
}
If (end)
{
Sprintf (write_buf, "# EXT-X-ENDLIST \ n ");
If (fwrite (write_buf, strlen (write_buf), 1, index_fp )! = 1)
{
Printf ("cocould not write last file and endlist tag to m3u8 index file \ n ");
Free (write_buf );
Fclose (index_fp );
Return-1;
}
}
Free (write_buf );
Fclose (index_fp );
Return 0;
}
Void slice_up ()
{
Int write_index = 1;
Unsigned int first_segment = 1; // The number of the first shard
Unsigned int last_segment = 0; // The last part number.
Int decode_done = 0; // whether the file is read successfully
Int remove_file = 0; // whether to remove the file (the partition written on the disk has reached the maximum)
Char remove_filename [256] = {0}; // name of the file to be deleted from the disk
Double prev_segment_time = 0; // time of the last shard
Int ret = 0;
Unsigned int actual_segment_durations [1024] = {0}; // the actual length of each part File
// Enter the name of the first output file
Sprintf (m_output_file_name, "% S % s-% u. Ts", url_prefix, output_prefix, m_output_index ++ );
//************************************** ** Create an output file (write header)
Init_mux ();
Write_index =! Write_index_file (first_segment, last_segment, 0, actual_segment_durations );
Do
{
Unsigned int current_segment_duration;
Double segment_time = prev_segment_time;
Avpacket packet;
Av_init_packet (& Packet );
Decode_done = av_read_frame (icodec, & Packet );
If (decode_done <0)
{
Break;
}
If (av_dup_packet (& Packet) <0)
{
Printf ("cocould not duplicate packet ");
Av_free_packet (& Packet );
Break;
}
If (packet. stream_index = video_stream_idx)
{
Segment_time = packet. PTs * av_q2d (icodec-> streams [video_stream_idx]-> time_base );
}
Else if (video_stream_idx <0)
{
Segment_time = packet. PTs * av_q2d (icodec-> streams [audio_stream_idx]-> time_base );
}
Else
{
Segment_time = prev_segment_time;
}
// This is to correct the error. If the file PTS is unavailable
If (packet. PTs <packet. DTS)
{
Packet. PTs = packet. DTS;
}
// Video
If (packet. stream_index = video_stream_idx)
{
If (vbsf_h1__to1_ B! = NULL)
{
Avpacket filteredpacket = packet;
Int A = av_bitstream_filter_filter (vbsf_h1__to1_ B,
Ovideo_st-> codec, null, & filteredpacket. Data, & filteredpacket. Size, packet. Data, packet. Size, packet. Flags & av_pkt_flag_key );
If (a> 0)
{
Av_free_packet (& Packet );
Packet. PTs = filteredpacket. PTS;
Packet. DTS = filteredpacket. DTS;
Packet. Duration = filteredpacket. duration;
Packet. Flags = filteredpacket. flags;
Packet. stream_index = filteredpacket. stream_index;
Packet. Data = filteredpacket. Data;
Packet. size = filteredpacket. size;
}
Else if (a <0)
{
Fprintf (stderr, "% s failed for stream % d, codec % s ",
Vbsf_h1__to1_ B-> filter-> name, packet. stream_index, ovideo_st-> codec? Ovideo_st-> codec-> name: "copy ");
Av_free_packet (& Packet );
Getchar ();
}
}
Packet. PTs = av_rescale_q_rnd (packet. pts, icodec-> streams [video_stream_idx]-> time_base, ovideo_st-> time_base, av_round_near_inf );
Packet. DTS = av_rescale_q_rnd (packet. DTS, icodec-> streams [video_stream_idx]-> time_base, ovideo_st-> time_base, av_round_near_inf );
Packet. Duration = av_rescale_q (packet. Duration, icodec-> streams [video_stream_idx]-> time_base, ovideo_st-> time_base );
Packet. stream_index = video_id; // The Order of add_out_stream is affected.
Printf ("video \ n ");
}
Else if (packet. stream_index = audio_stream_idx)
{
Packet. PTs = av_rescale_q_rnd (packet. pts, icodec-> streams [audio_stream_idx]-> time_base, oaudio_st-> time_base, av_round_near_inf );
Packet. DTS = av_rescale_q_rnd (packet. DTS, icodec-> streams [audio_stream_idx]-> time_base, oaudio_st-> time_base, av_round_near_inf );
Packet. Duration = av_rescale_q (packet. Duration, icodec-> streams [audio_stream_idx]-> time_base, oaudio_st-> time_base );
Packet. stream_index = audio_id; // The Order of add_out_stream is affected.
Printf ("audio \ n ");
}
Current_segment_duration = (INT) (segment_time-prev_segment_time + 0.5 );
Actual_segment_durations [last_segment] = (current_segment_duration> 0? Current_segment_duration: 1 );
If (segment_time-prev_segment_time> = segment_duration)
{
Ret = av_write_trailer (ocodec); // close ts file and free memory
If (Ret <0)
{
Printf ("Warning: cocould not av_write_trailer of stream \ n ");
}
Avio_flush (ocodec-> Pb );
Avio_close (ocodec-> Pb );
If (num_segments & (INT) (last_segment-first_segment)> = num_segments-1)
{
Remove_file = 1;
First_segment ++;
}
Else
{
Remove_file = 0;
}
If (write_index)
{
Write_index =! Write_index_file (first_segment, ++ last_segment, 0, actual_segment_durations );
}
If (remove_file)
{
Sprintf (remove_filename, "% S % s-% u. Ts", url_prefix, output_prefix, first_segment-1 );
Remove (remove_filename );
}
Sprintf (m_output_file_name, "% S % s-% u. Ts", url_prefix, output_prefix, m_output_index ++ );
If (avio_open (& ocodec-> Pb, m_output_file_name, avio_flag_write) <0)
{
Printf ("cocould not open '% s' \ n", m_output_file_name );
Break;
}
// Write a new header at the start of each file
If (avformat_write_header (ocodec, null ))
{
Printf ("cocould not write mpegts header to first output file \ n ");
Exit (1 );
}
Prev_segment_time = segment_time;
}
Ret = av_interleaved_write_frame (ocodec, & Packet );
If (Ret <0)
{
Printf ("Warning: cocould not write frame of stream \ n ");
}
Else if (Ret> 0)
{
Printf ("End of stream requested \ n ");
Av_free_packet (& Packet );
Break;
}
Av_free_packet (& Packet );
} While (! Decode_done );
//************************************** ** Complete the output file (write tail)
Uinit_mux ();
If (num_segments & (INT) (last_segment-first_segment)> = num_segments-1)
{
Remove_file = 1;
First_segment ++;
}
Else
{
Remove_file = 0;
}
If (write_index)
{
Write_index_file (first_segment, ++ last_segment, 1, actual_segment_durations );
}
If (remove_file)
{
Sprintf (remove_filename, "% S % s-% u. Ts", url_prefix, output_prefix, first_segment-1 );
Remove (remove_filename );
}
Return;
}
Effect:
Source Code address: http://download.csdn.net/detail/zhuweigangzwg/9456780
Add QQ Group for communication: 62054820
QQ: 379969650.
---------------------
Zwg tears
Source: csdn
Original: 50837005
Copyright Disclaimer: This article is an original article by the blogger. For more information, see the blog post link!
Generate an m3u8 file and a TS slicing program using the FFMPEG file (I)