Correct FFMPEG Settings Roku & HLS

If I use AWS Elastic Transcoder it creates compatible video with the Roku, however when I use the following the videos refuse to play, even though they will play fine in VLC player.

I am using this as a guide: https://www.drupal.org/forum/support/po … aybe-8-too

-hls_time 10 -hls_key_info_file keyinfo -hls_list_size 0 -hls_wrap 0 -hls_allow_cache 0 -start_number 1 -segment_format mpegts -copyts

Any thoughts to make it work properly?

It can be a number of things, like where are the files being served and are the proper headers set, or is CORS blocking the callback due to same-origin policy?
Keep in mind when you click on a video in VLC that is a direct link opposed to streaming it to the ROKU.

It could also be maybe the audio or video or both codecs are not compatible.

Also, is the end file an m3u8 or is it a ts and if so what is the streamFormat set to? I have found with containers that include or point to ts files that using streamFormat=“auto” works best.
Even with the ROKU stream tester none of the video format options will work unless auto is set for the format. It’s really odd.

That would be the main reasons as to why. I would like to ask why are you using Drupal instructions when you should be going with Apples instructions and guidelines. Which in that regards it could be the ffmpeg settings. Do you know if it saves the file as utf-8 encoded without BOM?

There is a free software called Handbrake which has long been around and they have settings based on ROKU outputs and its quite fast, might be your best solution to be honest with you.

I hope this has helped some and if you have questions feel free to ask.

It’s not a CORS issue, I just played back video that was created from AWS Elastic Transcoder and it worked fine, so its not a connection issue.
Main File

#EXTM3U
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=8628k,CODECS="avc1.640028,mp4a.40.2"
Bob-stream-high.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=6628k,CODECS="avc1.4d001f,mp4a.40.2"
Bob-stream-wifi4.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=5128k,CODECS="avc1.4d001f,mp4a.40.2"
Bob-stream-wifi3.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=3596k,CODECS="avc1.4d001f,mp4a.40.2"
Bob-stream-med.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=1296k,CODECS="avc1.42001f,mp4a.40.2"
Bob-stream-wifi1.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=664k,CODECS="avc1.42001e,avc1.66.30,mp4a.40.2"
Bob-stream-low.m3u8

Sub File

#EXTM3U
#EXT-X-VERSION:3
#EXT-X-ALLOW-CACHE:NO
#EXT-X-TARGETDURATION:13
#EXT-X-MEDIA-SEQUENCE:1
#EXT-X-KEY:METHOD=AES-128,URI="***URL HERE***"
#EXTINF:12.012000,
Bob-stream-high1.ts
#EXTINF:9.009000,
Bob-stream-high2.ts
#EXTINF:9.009000,
Bob-stream-high3.ts
#EXTINF:12.012000,
Bob-stream-high4.ts
#EXTINF:4.004000,
Bob-stream-high5.ts
#EXT-X-ENDLIST

Are you seeing any errors in the debugger?

none it is just stuck. I’m pretty baffled by it.

“bounce” wrote:
If I use AWS Elastic Transcoder it creates compatible video with the Roku, however when I use the following the videos refuse to play, even though they will play fine in VLC player.

I am using this as a guide: https://www.drupal.org/forum/support/po … aybe-8-too

-hls_time 10 -hls_key_info_file keyinfo -hls_list_size 0 -hls_wrap 0 -hls_allow_cache 0 -start_number 1 -segment_format mpegts -copyts

Any thoughts to make it work properly?
Here is what I’m using and works fine:

-vcodec copy -codec:a aac -f hls -hls_flags delete_segments

This works for converting a rtsp stream that is h.264 encoded.
Here is an example:

ffmpeg -loglevel error -thread_queue_size 512 -rtsp_transport +udp+tcp -rtsp_flags prefer_tcp -i rtsp://login:pass@192.168.1.64:554/Streaming/Channels/101?transportmode=unicast&profile=Profile_1 -vcodec copy -codec:a aac -f hls -hls_flags delete_segments /dev/shm/ggzEtQzhOE.m3u8

Thanks for sharing, I’m not using RTMP, so would it translate pretty well with something say a mp4, h264 type file?

I’m sharing a completed file example of what FFMPEG is passed and why the file fails to load in Roku. Its cleaned up a little to help you understand what is happening. Should I eliminate a parameter to make it compatible?

ffmpeg -re -i file.mov -y -threads 4 -preset ultrafast -c:a aac -strict -2 -b:a 64k -ac -c:v libx264 -x264opts keyint=90:min-keyint=90 -s 640x360 -b:v 600k 
-force_key_frames 90 -profile:v baseline -level 3.0 -hls_time 10 -hls_key_info_file key_info -hls_list_size 0 -hls_wrap 0 -hls_allow_cache 0 
-start_number 1 -segment_format mpegts -copyts file-stream-low.m3u8

“bounce” wrote:
Thanks for sharing, I’m not using RTMP, so would it translate pretty well with something say a mp4, h264 type file?

I’m sharing a completed file example of what FFMPEG is passed and why the file fails to load in Roku. Its cleaned up a little to help you understand what is happening. Should I eliminate a parameter to make it compatible?

ffmpeg -re -i file.mov -y -threads 4 -preset ultrafast -c:a aac -strict -2 -b:a 64k -ac -c:v libx264 -x264opts keyint=90:min-keyint=90 -s 640x360 -b:v 600k 
-force_key_frames 90 -profile:v baseline -level 3.0 -hls_time 10 -hls_key_info_file key_info -hls_list_size 0 -hls_wrap 0 -hls_allow_cache 0 
-start_number 1 -segment_format mpegts -copyts file-stream-low.m3u8

I’m not very knowledgeable in how to make ffmpeg work, I found my solution after searching a lot and testing what other people are using.
If your file is h.264, then yes, using

-vcodec copy -codec:a aac -f hls -hls_flags delete_segments file-stream.m3u8

should work fine.

Try something like

ffmpeg -re -i h264file.mp4 -vcodec copy -codec:a aac -f hls -hls_flags delete_segments file-stream.m3u8

Note, I didn’t try that command, I’m just guessing that is how it should look like.

I’m still having quite a fit with getting this working. What is even more frustrating is that Roku does not spit out an error, it just quits loading.

Can anybody else chime in on getting FFMPEG to work creating compliant files for Roku. Here is the Bash Script I’m using if it will help.

#!/bin/bash

VIDSOURCE="$1"
name=${VIDSOURCE%.*}
name=${name// /-} 
echo """$name"""

#generate encoding key
keyFile="$name.key"
#save encoding key to file
openssl rand 16 > $keyFile

#storing keyfile reference in a file
#if we are successfully adding SSL, then http should be changed into https
printf ''$keyFile'\r'$keyFile'\r' > keyinfo

#Parameters corresponding to https://developer.apple.com/library/ios/technotes/tn2224/_index.html#//apple_ref/doc/uid/DTS40009745-CH1-SETTINGSFILES

RESOLUTION3="640x360"
RESOLUTION4="640x360"
RESOLUTION5="960x540"
RESOLUTION6="1280x720"
RESOLUTION7="1280x720"
RESOLUTION8="1920x1080"
FRAMERATE3="29.97"
FRAMERATE4="29.97"
FRAMERATE5="29.97"
FRAMERATE6="29.97"
FRAMERATE7="29.97"
FRAMERATE8="29.97"
TOTALBITRATE3="664k"
TOTALBITRATE4="1296k"
TOTALBITRATE5="3596k"
TOTALBITRATE6="5128k"
TOTALBITRATE7="6628k"
TOTALBITRATE8="8628k"
VIDEOBITRATE3="600k"
VIDEOBITRATE4="1200k"
VIDEOBITRATE5="3500k"
VIDEOBITRATE6="5000k"
VIDEOBITRATE7="6500k"
VIDEOBITRATE8="8500k"
AUDIOBITRATE3="64k"
AUDIOBITRATE4="96k"
AUDIOBITRATE5="96k"
AUDIOBITRATE6="128k"
AUDIOBITRATE7="128k"
AUDIOBITRATE8="128k"
AUDIOSAMPLERATE="48k"
KEYFRAME3="90"
KEYFRAME4="90"
KEYFRAME5="90"
KEYFRAME6="90"
KEYFRAME7="90"
KEYFRAME8="90"
VPROFILE3="baseline"
VPROFILE4="baseline"
VPROFILE5="main"
VPROFILE6="main"
VPROFILE7="main"
VPROFILE8="high"
LEVEL3="3.0"
LEVEL4="3.1"
LEVEL5="3.1"
LEVEL6="3.1"
LEVEL7="3.1"
LEVEL8="4.0"
SEGMENTSIZE="9"
PRESET="ultrafast"

# the order is relevant, as players will start playing the first stream usually before checking bandwidth
# you should choose which bitrates you want to offer, comment out the rest
echo '#EXTM3U' > $name.m3u8
echo '#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH='$TOTALBITRATE8',CODECS="avc1.640028,mp4a.40.2"' >> $name.m3u8
echo $name'-stream-high.m3u8' >> $name.m3u8
echo '#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH='$TOTALBITRATE7',CODECS="avc1.4d001f,mp4a.40.2"' >> $name.m3u8
echo $name'-stream-wifi4.m3u8' >> $name.m3u8
echo '#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH='$TOTALBITRATE6',CODECS="avc1.4d001f,mp4a.40.2"' >> $name.m3u8
echo $name'-stream-wifi3.m3u8' >> $name.m3u8
echo '#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH='$TOTALBITRATE5',CODECS="avc1.4d001f,mp4a.40.2"' >> $name.m3u8
echo $name'-stream-med.m3u8' >> $name.m3u8
echo '#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH='$TOTALBITRATE4',CODECS="avc1.42001f,mp4a.40.2"' >> $name.m3u8
echo $name'-stream-wifi1.m3u8' >> $name.m3u8
echo '#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH='$TOTALBITRATE3',CODECS="avc1.42001e,avc1.66.30,mp4a.40.2"' >> $name.m3u8
echo $name'-stream-low.m3u8' >> $name.m3u8

AUDIO_OPTS3="-c:a aac -strict -2 -b:a $AUDIOBITRATE3 -ac 2"
AUDIO_OPTS4="-c:a aac -strict -2 -b:a $AUDIOBITRATE4 -ac 2"
AUDIO_OPTS5="-c:a aac -strict -2 -b:a $AUDIOBITRATE5 -ac 2"
AUDIO_OPTS6="-c:a aac -strict -2 -b:a $AUDIOBITRATE6 -ac 2"
AUDIO_OPTS7="-c:a aac -strict -2 -b:a $AUDIOBITRATE7 -ac 2"
AUDIO_OPTS8="-c:a aac -strict -2 -b:a $AUDIOBITRATE8 -ac 2"
VIDEO_OPTS3="-c:v libx264 -x264opts keyint=90:min-keyint=90 -s $RESOLUTION3 -b:v $VIDEOBITRATE3 -force_key_frames "expr:gte\(t,n_forced*$KEYFRAME3\)" -profile:v $VPROFILE3 -level $LEVEL3"
VIDEO_OPTS4="-c:v libx264 -x264opts keyint=90:min-keyint=90 -s $RESOLUTION4 -b:v $VIDEOBITRATE4 -force_key_frames "expr:gte\(t,n_forced*$KEYFRAME4\)" -profile:v $VPROFILE4 -level $LEVEL4"
VIDEO_OPTS5="-c:v libx264 -x264opts keyint=90:min-keyint=90 -s $RESOLUTION5 -b:v $VIDEOBITRATE5 -force_key_frames "expr:gte\(t,n_forced*$KEYFRAME5\)" -profile:v $VPROFILE5 -level $LEVEL5"
VIDEO_OPTS6="-c:v libx264 -x264opts keyint=90:min-keyint=90 -s $RESOLUTION6 -b:v $VIDEOBITRATE6 -force_key_frames "expr:gte\(t,n_forced*$KEYFRAME6\)" -profile:v $VPROFILE6 -level $LEVEL6"
VIDEO_OPTS7="-c:v libx264 -x264opts keyint=90:min-keyint=90 -s $RESOLUTION7 -b:v $VIDEOBITRATE7 -force_key_frames "expr:gte\(t,n_forced*$KEYFRAME7\)" -profile:v $VPROFILE7 -level $LEVEL7"
VIDEO_OPTS8="-c:v libx264 -x264opts keyint=90:min-keyint=90 -s $RESOLUTION8 -b:v $VIDEOBITRATE8 -force_key_frames "expr:gte\(t,n_forced*$KEYFRAME8\)" -profile:v $VPROFILE8 -level $LEVEL8"

#if you want no segments and just one big file, choose one line or the other
#OUTPUT_HLS="-hls_time 10 -hls_list_size 0 -hls_wrap 0 -hls_allow_cache 0 -start_number 1 -segment_format mpegts -copyts -hls_flags single_file" #one big file
OUTPUT_HLS="-hls_time 10 -hls_key_info_file keyinfo -hls_list_size 0 -hls_wrap 0 -hls_allow_cache 0 -start_number 1 -segment_format mpegts -copyts" #multiple segments

ffmpeg -re -i "$VIDSOURCE" -y -threads 4 -preset $PRESET \
$AUDIO_OPTS3 $VIDEO_OPTS3 $OUTPUT_HLS $name-stream-low.m3u8 \
$AUDIO_OPTS5 $VIDEO_OPTS5 $OUTPUT_HLS $name-stream-med.m3u8 \
$AUDIO_OPTS8 $VIDEO_OPTS8 $OUTPUT_HLS $name-stream-high.m3u8 \
$AUDIO_OPTS4 $VIDEO_OPTS4 $OUTPUT_HLS $name-stream-wifi1.m3u8 \
$AUDIO_OPTS6 $VIDEO_OPTS6 $OUTPUT_HLS $name-stream-wifi3.m3u8 \
$AUDIO_OPTS7 $VIDEO_OPTS7 $OUTPUT_HLS $name-stream-wifi4.m3u8 \

rm keyinfo

Have you tried it without the encryption? Try using the first “OUTPUT_HLS=” line instead of the second and see if it works.

-JT

Error Spit Out with Non-Encrypted Video Modification:

Warning occurred while setting a field of an RoSGNode
– Tried to set nonexistent field “streamformat” of a “Video” node
at line 111 of file pkg:/source/PlayerTask.brs

That Line is as expected…
video.streamformat = “hls”

Plays HLS fine from CloudFront from VLC Player.. Seems like a format issue that Roku doesn’t like. Here is the main HLS File

#EXTM3U
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=8628k,CODECS="avc1.640028,mp4a.40.2"
final-stream-high.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=6628k,CODECS="avc1.4d001f,mp4a.40.2"
final-stream-wifi4.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=5128k,CODECS="avc1.4d001f,mp4a.40.2"
final-stream-wifi3.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=3596k,CODECS="avc1.4d001f,mp4a.40.2"
final-stream-med.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=1296k,CODECS="avc1.42001f,mp4a.40.2"
final-stream-wifi1.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=664k,CODECS="avc1.42001e,avc1.66.30,mp4a.40.2"
final-stream-low.m3u8

And Supporting Cast Member:

#EXTM3U
#EXT-X-VERSION:3
#EXT-X-ALLOW-CACHE:NO
#EXT-X-TARGETDURATION:11
#EXT-X-MEDIA-SEQUENCE:1
#EXTINF:10.535333,
final-stream-low1.ts
#EXTINF:10.514000,
final-stream-low2.ts
#EXTINF:8.978622,
final-stream-low3.ts
#EXT-X-ENDLIST

Also Attaching Debug Info From VideoSpec

Here is the File that Works:

***** Analyzed File Results *****

*** General Parameters ***
- Name:  HLS_15M_00001.ts 
- Container:  Mpeg Transport Stream 
- Size:  1.25 MB 
- Duration:  6s 6ms 
- Bitrate:  1 075 Kbps 

*** Video Track Parameters ***
- Format:  H.264/MPEG-4 AVC 
- Bitrate:  Max.: --- / Average: 893 Kbps / Min.: --- 
- Frame rate (fps):  Max.: Undefined / Average: 59.940 / Min.: Undefined 
- Encoding profile:  Main@L3.1 
- Image size:  960*540 
- Pixel Aspect Ratio:  Undefined 
- Display Aspect Ratio:  16:9 
- Interlacing:  Progressive 

*** First Audio Track Parameters ***
- Format:  AAC - MPEG-4 audio 
- Bitrate:  127 Kbps 
- Resolution:  Undefined 
- Rate:  44.1 KHz 
- Channel(s):  2 (stereo) 
- Position:  Front: L R 

*** Miscellaneous ***
- Subtitle(s): No Subtitle
- Album: Undefined
- Performer: Undefined
- Genre: Undefined
- Encoded date: Undefined
- Album artist: Undefined

Video That Doesn’t Work:

***** Analyzed File Results *****

*** General Parameters ***
- Name:  final-stream-high2.ts 
- Container:  Mpeg Transport Stream 
- Size:  11.01 MB 
- Duration:  9s 309ms 
- Bitrate:  9 463 Kbps 

*** Video Track Parameters ***
- Format:  H.264/MPEG-4 AVC 
- Bitrate:  Max.: --- / Average: --- / Min.: --- 
- Frame rate (fps):  Max.: Undefined / Average: 119.880 / Min.: Undefined 
- Encoding profile:  High@L4.0 
- Image size:  1920*1080 
- Pixel Aspect Ratio:  Undefined 
- Display Aspect Ratio:  16:9 
- Interlacing:  Progressive 

*** First Audio Track Parameters ***
- Format:  AAC - MPEG-4 audio 
- Bitrate:  Undefined 
- Resolution:  Undefined 
- Rate:  48.0 KHz 
- Channel(s):  2 (stereo) 
- Position:  Front: L R 

*** Miscellaneous ***
- Subtitle(s): No Subtitle
- Album: Undefined
- Performer: Undefined
- Genre: Undefined
- Encoded date: Undefined
- Album artist: Undefined

So I guess my questions comparing the results are as followed:
No Video Bitrate? High Frame Rate? Differing Encoding Profile? No Audio Bitrate? High Sample Rate? 44khz vs 48?

If one of these is bad, how shall I go about correcting?

Edit: Fixed it!

There is a trailing “0” in your OUTPUT_HLS statement. In addition, -hls_wrap has been deprecated.

I also added -report to trace issues.

OUTPUT_HLS="-hls_time 10 -hls_key_info_file keyinfo -hls_list_size 0 -hls_flags delete_segments -hls_allow_cache 0 -start_number 1 -segment_format mpegts -copyts -report" #multiple segments