ffmpeghttp-live-streamingmpeg-dashhls.js

Is it possible to pregenerate m3u8 file? (the playlist only) and skip the transcoding?


I am trying to create a media server, and only want to transcode video when it's played. However I need the playlist in advance so that the client play can load the video metadata. Is this possible?

I want to do something like this:

Client -> GET m3u8 (pregenerated in advance)
Client -> GET ts -> Transcode only this single ts file
Client -> GET ts -> Transcode only this single ts file
Client -> GET ts -> Transcode only this single ts file

I don't want to transcode the entire video at once, I want to be able to only transcode the part that is requested.

Is this possible? Also open to using MPEG-DASH instead if needed.


Solution

  • my solution was generate the m3u8 myself according to the video total duration and serve it first.

    before running ffmpeg, using the requested segement number to generate start seconds and put it after the '-ss' to ffmpeg command options, and you must specify the '-r' option to match your hls_time and fps for the final ts segement time matching your predefined segment duration.Or you will get wrong ts duration for below

    root@YOLE-UJIK:~/tran_6# cat generated_by_ffmpeg.m3u8 
    #EXTM3U
    #EXT-X-VERSION:3
    #EXT-X-TARGETDURATION:5
    #EXT-X-MEDIA-SEQUENCE:0
    #EXT-X-PLAYLIST-TYPE:VOD
    #EXTINF:5.005000,
    stream0_0.ts
    #EXTINF:5.005000,
    stream0_1.ts
    #EXTINF:5.005000,
    stream0_2.ts
    #EXTINF:5.005000,
    stream0_3.ts
    #EXTINF:5.005000,
    stream0_4.ts
    #EXTINF:5.005000,
    stream0_5.ts
    #EXTINF:4.971633,
    stream0_6.ts
    #EXTINF:5.005000,
    stream0_7.ts
    
    
    

    For example

    I was using golang as hls serve code language, my segment duration was predefined as 5s

    I generate the m3u8 part using video total duration and my segment duation options, the code below show how to write the preserve m3u8:

    func BuildMainPlaylistTranscoding(opt Sw, segmentDuration float64) string {
    
        segmentDurationsSeconds := []float64{}
        totalDuration := float64(opt.Duration)
        standardPartSegDuration := segmentDuration
        for ; totalDuration > 0; totalDuration -= standardPartSegDuration {
            if totalDuration > standardPartSegDuration {
                segmentDurationsSeconds = append(segmentDurationsSeconds, standardPartSegDuration)
            } else {
                segmentDurationsSeconds = append(segmentDurationsSeconds, totalDuration)
            }
        }
    
        buildder := strings.Builder{}
        buildder.WriteString(fmt.Sprintf(`#EXTM3U
    #EXT-X-VERSION:3
    #EXT-X-TARGETDURATION:%d
    #EXT-X-MEDIA-SEQUENCE:0
    #EXT-X-PLAYLIST-TYPE:VOD`, 6))
        // apple must end with .ts, otherwise safari will not request ts data
        for index := 0; index < len(segmentDurationsSeconds); index++ {
            buildder.WriteString(fmt.Sprintf("\n#EXTINF:%.3f,\nstream0_%d.ts", segmentDurationsSeconds[index], index))
        }
        buildder.WriteString(fmt.Sprintf("\n#EXT-X-ENDLIST"))
        return buildder.String()
    }
    

    When the media segement http request arrived, i'm using the ffmpeg command below to generate ts segment and serve.

    ffmpeg -hide_banner -analyzeduration 200M -init_hw_device vaapi=va:/dev/dri/renderD128 -filter_hw_device va -hwaccel vaapi -hwaccel_output_format vaapi -i "/data/user/admin/Downloads/迪迦奥特曼 EP48 -月球来的逃亡者1080P.mkv" -copyts -autoscale 0 -map_metadata -1 -map_chapters -1 -threads 0 -codec:v:0 h264_vaapi -b:v 1000000 -r 30 -force_key_frames "expr:gte(t,n_forced*5)" -filter_complex "[0:3]scale=s=960x720:flags=fast_bilinear[sub];[0:0]setparams=color_primaries=bt709:color_trc=bt709:colorspace=bt709,scale_vaapi=w=960:h=720:format=nv12:extra_hw_frames=24,hwdownload,format=nv12[main];[main][sub]overlay=eof_action=pass:shortest=1:repeatlast=0,hwupload_vaapi" -start_at_zero -codec:a:0 aac -ac 2 -ab 128000 -max_muxing_queue_size 2048 -f hls -start_number 0 -hls_time 5 -hls_segment_type mpegts -hls_list_size 0 -hls_segment_filename "/root/tran_7/stream0_%d.ts" -hls_playlist_type vod "/root/tran_7/generated_by_ffmpeg.m3u8"
    
    

    The video ffprobe data was below

     "streams": [
            {
                "index": 0,
                "codec_name": "hevc",
                "codec_long_name": "H.265 / HEVC (High Efficiency Video Coding)",
                "profile": "Main 10",
                "codec_type": "video",
                "codec_tag_string": "[0][0][0][0]",
                "codec_tag": "0x0000",
                "width": 1440,
                "height": 1080,
                "coded_width": 1440,
                "coded_height": 1080,
                "closed_captions": 0,
                "film_grain": 0,
                "has_b_frames": 2,
                "sample_aspect_ratio": "1:1",
                "display_aspect_ratio": "4:3",
                "pix_fmt": "yuv420p10le",
                "level": 120,
                "color_range": "tv",
                "color_space": "bt709",
                "chroma_location": "left",
                "refs": 1,
                "r_frame_rate": "30000/1001",
                "avg_frame_rate": "30000/1001",
                "time_base": "1/1000",
                "start_pts": 0,
                "start_time": "0.000000",
                "extradata": "\n00000000: 0102 2000 0000 9000 0000 0000 78f0 00fc  .. .........x...\n00000010: fdfa fa00 0047 0420 0001 0019 4001 0c01  .....G. ....@...\n00000020: ffff 0220 0000 0300 9000 0003 0000 0300  ... ............\n00000030: 7895 8802 4021 0001 002c 4201 0102 2000  x...@!...,B... .\n00000040: 0003 0090 0000 0300 0003 0078 a002 d080  ...........x....\n00000050: 10e4 d965 622e 4c2a 6a04 0402 0800 001f  ...eb.L*j.......\n00000060: 4800 03a9 8040 2200 0100 0844 01c1 7329  H....@\"....D..s)\n00000070: 59c6 c927 0001 00a4 4e01 059f 2ca2 de09  Y..'....N...,...\n00000080: b517 47db bb55 a4fe 7fc2 fc4e 7832 3635  ..G..U.....Nx265\n00000090: 202d 202d 2048 2e32 3635 2f48 4556 4320   - - H.265/HEVC \n000000a0: 636f 6465 6320 2d20 436f 7079 7269 6768  codec - Copyrigh\n000000b0: 7420 3230 3133 2d32 3031 3637 2028 6329  t 2013-20167 (c)\n000000c0: 204d 756c 7469 636f 7265 7761 7265 2c20   Multicoreware, \n000000d0: 496e 6320 2d20 6874 7470 3a2f 2f78 3236  Inc - http://x26\n000000e0: 352e 6f72 6720 2d20 6f70 7469 6f6e 733a  5.org - options:\n000000f0: 2063 7075 6964 3d31 3137 3335 3033 2066   cpuid=1173503 f\n00000100: 7261 6d65 2d74 6872 6561 6473 3d33 206e  rame-threads=3 n\n00000110: 756d 612d 706f 6f6c 733d 3880            uma-pools=8.\n",
                "extradata_size": 284,
                "disposition": {
                    "default": 1,
                    "dub": 0,
                    "original": 0,
                    "comment": 0,
                    "lyrics": 0,
                    "karaoke": 0,
                    "forced": 1,
                    "hearing_impaired": 0,
                    "visual_impaired": 0,
                    "clean_effects": 0,
                    "attached_pic": 0,
                    "timed_thumbnails": 0,
                    "captions": 0,
                    "descriptions": 0,
                    "metadata": 0,
                    "dependent": 0,
                    "still_image": 0
                },
                "tags": {
                    "language": "jpn",
                    "BPS": "4652198",
                    "BPS-eng": "4652198",
                    "DURATION": "00:24:27.466000000",
                    "DURATION-eng": "00:24:27.466000000",
                    "NUMBER_OF_FRAMES": "43980",
                    "NUMBER_OF_FRAMES-eng": "43980",
                    "NUMBER_OF_BYTES": "853367844",
                    "NUMBER_OF_BYTES-eng": "853367844",
                    "_STATISTICS_WRITING_APP": "mkvmerge v8.5.2 ('Crosses') 64bit",
                    "_STATISTICS_WRITING_APP-eng": "mkvmerge v8.5.2 ('Crosses') 64bit",
                    "_STATISTICS_WRITING_DATE_UTC": "2017-08-13 13:20:32",
                    "_STATISTICS_WRITING_DATE_UTC-eng": "2017-08-13 13:20:32",
                    "_STATISTICS_TAGS": "BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES",
                    "_STATISTICS_TAGS-eng": "BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES"
                }
            },
            {
                "index": 1,
                "codec_name": "ac3",
                "codec_long_name": "ATSC A/52A (AC-3)",
                "codec_type": "audio",
                "codec_tag_string": "[0][0][0][0]",
                "codec_tag": "0x0000",
                "sample_fmt": "fltp",
                "sample_rate": "48000",
                "channels": 2,
                "channel_layout": "stereo",
                "bits_per_sample": 0,
                "initial_padding": 0,
                "r_frame_rate": "0/0",
                "avg_frame_rate": "0/0",
                "time_base": "1/1000",
                "start_pts": 0,
                "start_time": "0.000000",
                "bit_rate": "384000",
                "extradata": "\n",
                "disposition": {
                    "default": 1,
                    "dub": 0,
                    "original": 0,
                    "comment": 0,
                    "lyrics": 0,
                    "karaoke": 0,
                    "forced": 1,
                    "hearing_impaired": 0,
                    "visual_impaired": 0,
                    "clean_effects": 0,
                    "attached_pic": 0,
                    "timed_thumbnails": 0,
                    "captions": 0,
                    "descriptions": 0,
                    "metadata": 0,
                    "dependent": 0,
                    "still_image": 0
                },
                "tags": {
                    "language": "chi",
                    "BPS": "384000",
                    "BPS-eng": "384000",
                    "DURATION": "00:24:27.456000000",
                    "DURATION-eng": "00:24:27.456000000",
                    "NUMBER_OF_FRAMES": "45858",
                    "NUMBER_OF_FRAMES-eng": "45858",
                    "NUMBER_OF_BYTES": "70437888",
                    "NUMBER_OF_BYTES-eng": "70437888",
                    "_STATISTICS_WRITING_APP": "mkvmerge v8.5.2 ('Crosses') 64bit",
                    "_STATISTICS_WRITING_APP-eng": "mkvmerge v8.5.2 ('Crosses') 64bit",
                    "_STATISTICS_WRITING_DATE_UTC": "2017-08-13 13:20:32",
                    "_STATISTICS_WRITING_DATE_UTC-eng": "2017-08-13 13:20:32",
                    "_STATISTICS_TAGS": "BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES",
                    "_STATISTICS_TAGS-eng": "BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES"
                }
            },
            {
                "index": 2,
                "codec_name": "flac",
                "codec_long_name": "FLAC (Free Lossless Audio Codec)",
                "codec_type": "audio",
                "codec_tag_string": "[0][0][0][0]",
                "codec_tag": "0x0000",
                "sample_fmt": "s16",
                "sample_rate": "48000",
                "channels": 2,
                "channel_layout": "stereo",
                "bits_per_sample": 0,
                "initial_padding": 0,
                "r_frame_rate": "0/0",
                "avg_frame_rate": "0/0",
                "time_base": "1/1000",
                "start_pts": 0,
                "start_time": "0.000000",
                "bits_per_raw_sample": "16",
                "extradata": "\n00000000: 1000 1000 0000 1000 2ec2 0bb8 02f0 0432  ...............2\n00000010: cea0 06c0 50fc 36d6 8e6d fb18 551a c62e  ....P.6..m..U...\n00000020: ac3e                                     .>\n",
                "extradata_size": 34,
                "disposition": {
                    "default": 0,
                    "dub": 0,
                    "original": 0,
                    "comment": 0,
                    "lyrics": 0,
                    "karaoke": 0,
                    "forced": 0,
                    "hearing_impaired": 0,
                    "visual_impaired": 0,
                    "clean_effects": 0,
                    "attached_pic": 0,
                    "timed_thumbnails": 0,
                    "captions": 0,
                    "descriptions": 0,
                    "metadata": 0,
                    "dependent": 0,
                    "still_image": 0
                },
                "tags": {
                    "language": "jpn",
                    "BPS": "662320",
                    "BPS-eng": "662320",
                    "DURATION": "00:24:27.470000000",
                    "DURATION-eng": "00:24:27.470000000",
                    "NUMBER_OF_FRAMES": "17197",
                    "NUMBER_OF_FRAMES-eng": "17197",
                    "NUMBER_OF_BYTES": "121492010",
                    "NUMBER_OF_BYTES-eng": "121492010",
                    "_STATISTICS_WRITING_APP": "mkvmerge v8.5.2 ('Crosses') 64bit",
                    "_STATISTICS_WRITING_APP-eng": "mkvmerge v8.5.2 ('Crosses') 64bit",
                    "_STATISTICS_WRITING_DATE_UTC": "2017-08-13 13:20:32",
                    "_STATISTICS_WRITING_DATE_UTC-eng": "2017-08-13 13:20:32",
                    "_STATISTICS_TAGS": "BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES",
                    "_STATISTICS_TAGS-eng": "BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES"
                }
            },
            {
                "index": 3,
                "codec_name": "hdmv_pgs_subtitle",
                "codec_long_name": "HDMV Presentation Graphic Stream subtitles",
                "codec_type": "subtitle",
                "codec_tag_string": "[0][0][0][0]",
                "codec_tag": "0x0000",
                "r_frame_rate": "0/0",
                "avg_frame_rate": "0/0",
                "time_base": "1/1000",
                "start_pts": 0,
                "start_time": "0.000000",
                "duration_ts": 1467470,
                "duration": "1467.470000",
                "extradata": "\n",
                "disposition": {
                    "default": 1,
                    "dub": 0,
                    "original": 0,
                    "comment": 0,
                    "lyrics": 0,
                    "karaoke": 0,
                    "forced": 1,
                    "hearing_impaired": 0,
                    "visual_impaired": 0,
                    "clean_effects": 0,
                    "attached_pic": 0,
                    "timed_thumbnails": 0,
                    "captions": 0,
                    "descriptions": 0,
                    "metadata": 0,
                    "dependent": 0,
                    "still_image": 0
                },
                "tags": {
                    "language": "chi",
                    "BPS": "10374",
                    "BPS-eng": "10374",
                    "DURATION": "00:23:32.111000000",
                    "DURATION-eng": "00:23:32.111000000",
                    "NUMBER_OF_FRAMES": "564",
                    "NUMBER_OF_FRAMES-eng": "564",
                    "NUMBER_OF_BYTES": "1831328",
                    "NUMBER_OF_BYTES-eng": "1831328",
                    "_STATISTICS_WRITING_APP": "mkvmerge v8.5.2 ('Crosses') 64bit",
                    "_STATISTICS_WRITING_APP-eng": "mkvmerge v8.5.2 ('Crosses') 64bit",
                    "_STATISTICS_WRITING_DATE_UTC": "2017-08-13 13:20:32",
                    "_STATISTICS_WRITING_DATE_UTC-eng": "2017-08-13 13:20:32",
                    "_STATISTICS_TAGS": "BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES",
                    "_STATISTICS_TAGS-eng": "BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES"
                }
            }
        ],
        "format": {
            "filename": "/data/user/admin/Downloads/迪迦奥特曼 EP48 -月球来的逃亡者1080P.mkv",
            "nb_streams": 4,
            "nb_programs": 0,
            "format_name": "matroska,webm",
            "format_long_name": "Matroska / WebM",
            "start_time": "0.000000",
            "duration": "1467.470000",
            "size": "1047593097",
            "bit_rate": "5711016",
            "probe_score": 100,
            "tags": {
                "encoder": "libebml v1.3.3 + libmatroska v1.4.4",
                "creation_time": "2017-08-13T13:20:32.000000Z"
            }
        }
    }