FFmpeg solves the HLS drag-and-drop problem

Source: Internet
Author: User

Apple's HLS Solution uses the FFMPEG transcoded TS stream, which will gradually become non-synchronous during playback. The solution of Sohu source is to add the discontinue tag every five minutes, however, this tag causes the native player to restart, with a bit of cards. In this case, it is better to rebuild the player without restarting and directly read the next stream. However, there are other problems with FFMPEG processing HLS playback: 1. Each time a discontinue occurs, the displayed playback duration is cleared; 2. You can only drag and drop the content before the first discontinue. In this article, FFmpeg is transformed to adapt HLS sources more elegantly.

Modify the HLS. c file. You can use ffplay for comparison before and after verification.

1. Add a function

Static int find_timestamp_in_seq_no (struct playlist * PLS, int64_t * timestamp, int seq_no)

{

Int I;

* Timestamp = 0;

For (I = 0; I <seq_no; I ++ ){

* Timestamp + = PLS-> segments [I]-> duration;

}

Return 0;

}

2. Modify the function:

Struct segment {

Int64_t duration;

Int64_t url_offset;

Int64_t size;

Char * URL;

Char * key;

Enum keytype key_type;

Uint8_t IV [16];

Int64_t first_dts; // added in this article

};

Static int hls_read_packet (avformatcontext * s, avpacket * Pkt)

{

Hlscontext * c = s-> priv_data;

Int ret, I, minplaylist =-1;

Int64_t timestamp = av_nopts_value;

Static int64_t lastdts [2] = {av_nopts_value };

Static int64_t lastdts_fix [2] = {av_nopts_value };

Static int64_t interdts [2] = {av_nopts_value };

Static int64_t whole_dts [2] = {av_nopts_value}; // accumulated DTS

Recheck_discard_flags (S, C-> first_packet );

For (I = 0; I <c-> n_playlists; I ++ ){

Struct playlist * PLS = C-> playlists [I];

/* Make sure we 've got one buffered packet from each open playlist

* Stream */

Avrational TB;

TB = get_timebase (PLS );

Find_timestamp_in_seq_no (PLS, & timestamp, pls-> cur_seq_no );

If (PLS-> needed &&! Pls-> Pkt. Data ){

While (1 ){

Int64_t ts_diff;

Ret = av_read_frame (PLS-> CTX, & PLS-> Pkt );

If (Ret <0 ){

If (! Url_feof (& PLS-> Pb) & RET! = Averror_eof)

Return ret;

Reset_packet (& PLS-> Pkt );

Break;

} Else {

// Save the first timestamp of each segments and use it as the seek to the new discontinue. It is not required to be accurate.

If (PLS-> segments [PLS-> cur_seq_no]-> first_dts = av_nopts_value)

{

Pls-> segments [PLS-> cur_seq_no]-> first_dts = PLS-> Pkt. DTS;

// Av_log (S, av_log_error, "seq_no = % d, DTS = % LLD \ n", pls-> cur_seq_no, pls-> Pkt. DTS );

}

/* Stream_index check prevents matching picture attachments etc .*/

If (PLS-> is_id3_timestamped & PLS-> Pkt. stream_index = 0 ){

/* Audio elementary streams are ID3 timestamped */

Fill_timing_for_id3_timestamped_stream (PLS );

}

If (c-> first_timestamp = av_nopts_value &&

Pls-> Pkt. DTS! = Av_nopts_value)

C-> first_timestamp = av_rescale_q (PLS-> Pkt. DTS,

Get_timebase (PLS), av_time_base_q );

}

If (PLS-> seek_timestamp = av_nopts_value)

{

// When the current timestamp is normal, it is assigned to lastdts

If (PLS-> Pkt. PTs> lastdts [PLS-> Pkt. stream_index])

{

// Save the last timestamp as the right value accumulated next time. The PTS of the last frame is the same as that of DTs, so it can be shared.

Lastdts [PLS-> Pkt. stream_index] = PLS-> Pkt. DTS;

}

Else // when the discontinue is encountered, it is accumulated to whole_dts.

{

Whole_dts [PLS-> Pkt. stream_index] + = lastdts [PLS-> Pkt. stream_index];

Lastdts [PLS-> Pkt. stream_index] = PLS-> Pkt. DTS;

Av_log (S, av_log_error, "DTS = % LLD, Index = % d \ n", whole_dts [PLS-> Pkt. stream_index], pls-> Pkt. stream_index );

}

// When whole_dts has a value, add it to the data transmission in read packet to obtain the incremental data transmission.

If (whole_dts [PLS-> Pkt. stream_index]! = Av_nopts_value)

{

// Av_log (S, av_log_error, "lastdts = % LLD, % LLD \ n", lastdts, pls-> Pkt. DTS );

Pls-> Pkt. DTS + = interdts [PLS-> Pkt. stream_index] + whole_dts [PLS-> Pkt. stream_index];

Pls-> Pkt. PTS + = interdts [PLS-> Pkt. stream_index] + whole_dts [PLS-> Pkt. stream_index];

}

// Calculate the audio/video interval value, which is subject to DTS

If (interdts [PLS-> Pkt. stream_index] = av_nopts_value &&

Lastdts [PLS-> Pkt. stream_index]! = Av_nopts_value)

{

Interdts [PLS-> Pkt. stream_index] = PLS-> Pkt. DTS-lastdts [PLS-> Pkt. stream_index];

Av_log (S, av_log_error, "Inter DTS = % LLD, Index = % d \ n", interdts, pls-> Pkt. stream_index );

}

Break;

}

Else // seek, you need to save the lastdts of the previous discontinue

{

// Whole_dts [0] + = lastdts [PLS-> Pkt. stream_index];

// Whole_dts [1] + = lastdts [PLS-> Pkt. stream_index];

}

If (PLS-> seek_stream_index <0 |

Pls-> seek_stream_index = PLS-> Pkt. stream_index ){

If (PLS-> Pkt. DTS = av_nopts_value ){

Pls-> seek_timestamp = av_nopts_value;

Break;

}

Ts_diff = timestamp + av_rescale_rnd (PLS-> Pkt. DTS-pls-> segments [PLS-> cur_seq_no]-> first_dts, av_time_base,

TB. Den, av_round_down)-pls-> seek_timestamp;

If (ts_diff> = 0 & (PLS-> seek_flags & avseek_flag_any |

Pls-> Pkt. Flags & av_pkt_flag_key )){

Whole_dts [0] = (PLS-> seek_timestamp + ts_diff) * TB. den/(Tb. Num * av_time_base)-pls-> Pkt. DTS;

Whole_dts [1] = (PLS-> seek_timestamp + ts_diff) * TB. den/(Tb. Num * av_time_base)-pls-> Pkt. DTS;

Av_log (S, av_log_error, "whold DTS = % LLD, DTS = % LLD \ n", whole_dts [0], pls-> Pkt. DTS );

Pls-> seek_timestamp = av_nopts_value;

Break;

}

}

Av_free_packet (& PLS-> Pkt );

Reset_packet (& PLS-> Pkt );

}

}

/* Check if this stream has the packet with the lowest DTS */

If (PLS-> Pkt. Data ){

Struct playlist * minpls = minplaylist <0?

Null: C-> playlists [minplaylist];

If (minplaylist <0 ){

Minplaylist = I;

} Else {

Int64_t DTS = PLS-> Pkt. DTS;

Int64_t mindts = minpls-> Pkt. DTS;

If (DTS = av_nopts_value |

(Mindts! = Av_nopts_value & compare_ts_with_wrapdetect (DTS, PLS, mindts, minpls) <0 ))

Minplaylist = I;

}

}

}

/* If we got a packet, return it */

If (minplaylist> = 0 ){

Struct playlist * PLS = C-> playlists [minplaylist];

* Pkt = PLS-> Pkt;

Pkt-> stream_index + = PLS-> stream_offset;

Reset_packet (& C-> playlists [minplaylist]-> Pkt );

If (Pkt-> DTS! = Av_nopts_value)

C-> cur_timestamp = av_rescale_q (Pkt-> DTS,

Pls-> CTX-> streams [PLS-> Pkt. stream_index]-> time_base,

Av_time_base_q );

Return 0;

}

Return averror_eof;

}


This article is from the "A Jun" blog. For more information, contact the author!

FFmpeg solves the HLS drag-and-drop problem

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.