Generate an m3u8 file and a TS slicing program using the FFMPEG file (I)

Source: Internet
Author: User

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)

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.