This method works a lot better than the first method. It works with phones, windows, Linux and other devices that support HLS. Mainly in this blog post we will be streaming to VLC Player. VLC Player is available for the phone and windows. HLS stands for HTTP Live Stream. You will also use a RAM Disk to store the stream pieces on. Don’t worry, you only need 32MB of RAM free, since your storing 5 video files that are 5-seconds each. We use a RAM Disk because its faster since it is not a motorized disk(like a HDD) and when computer loses power all files on that disk are gone. It writes 5 files, after the 5th file is done it deletes the first file and creates a new one. Plus it stores a M3U8 Playlist that is updated everytime a new file is created.
The steps
- Install Unreal Live Server and Unreal Media Server. See the first blog post here for instructions you don’t need the archival server. Also Microsoft Internet Information Services(if not installed).
- Install SoftPerfect RAMDisk from MajorGeeks not the offical website. MajorGeeks have the freeware version. The newer ones are shareware and are not free.
- After installing the RAM Disk open RAM Disk control panel up and add a ramdrive NTFS Formatted and 32MB of memory.
- After that download the HLS Configurator tool for IIS. Its a tool that I made that will configure the .m3u8 MIME type and set UMediaServer service startup type to Manual. Make sure to put that file somewhere the file can always be available on the computer.
- Next run the tool as administrator, and tell it the drive letter of the RAM Drive that was mounted. If you get an error saying that a file could not be found, then you probably didn’t install Unreal Media Server
- Next in the RAM Disk control panel click Tools then Applications then add the downloaded tool to the list. This will create the IIS Config file and start UMediaServer service after the drive is mounted on next restart.
- Next open Internet Information Services Manager from Administrative Tools
- If you want to use the orignal Port# delete the Default Website
- Right click The Sites folder and click Add Website…
- For Site Name type My TV if you are wanting to keep the default website type port 8321 for the port.
- For Physical path type the root path of the RAMDisk. For example if its Drive V then the root path is V:\
- Click Connect as… button and enter a administrator Username and password that is used in Windows
- Click OK button on all Windows
- Next open Unreal Media Server Configuration tool
- Right click the TV live broadcast that you named and click Start HLS Broadcasting…
- Enter the website URL of your TV stream for example if your hostname is delphijustintv.com then enter http://delphijustintv.com But if you are using port 8321 then its http://delphijustintv.com:8321
- For the Web Folder path enter the root of the RAMDisk. For example Drive V will be V:\
- Check always running.
- Click OK. Your all done now in VLC Media player it should play the TV stream. You will have to open tv.m3u8 or whatever file in the ram drive that ends with .m3u8. So for tv.m3u8 and http://delphijustintv.com as root URL will be http://delphijustintv.com/tv.m3u8 or if it uses port 8321 http://delphijustintv.com:8321/tv.m3u8
program HLSIIS; {$RESOURCE HLS-IIS-DATA.RES} { This is the source code. HLS Configurator for Microsoft Internet Information Services You will need Unreal Media Server. } uses SysUtils,math, windows, dialogs, Classes, shellapi; const appkey='Software\Justin\TVStreaming';//settings key name EVENTLOG_TYPES:dword=EVENTLOG_INFORMATION_TYPE or eventlog_warning_type; REG_RAMDISK='RAMDisk';//Registry Value that has the Drive Letter ServiceManual:dword=3;//Manual Service Startup type AppName='TV Streaming';//The name of this tool type ERegistry=class(Exception);//Registry error exception ENet_exe=class(exception);//net.exe execution error exception var hk:hkey=0;//Tool setting key hksrv:hkey=0;//Service Key S:String='V';//String that contains the drive letter DriveLetter:AnsiChar;//Drive letter WebConfig:tresourcestream;//web.config file rs,dispConfig,Error:dword;//some dword variables regerror:longint;//registry error variable UMediaServer:Shellexecuteinfo;//net.exe execution info variable HEL:thandle;//eventlog handle label setRamdisk;//for retrying when a bad drive letter has been typed in procedure InstallEventLog; { Installs this tool for errors to be put in the event log. } var hk:hkey; disp:Dword; begin regcreatekeyex(HKEY_LOCAL_MACHINE, 'SYSTEM\CurrentControlSet\Services\Eventlog\Application\HLS-IIS',0,NIL, REG_OPTION_NON_VOLATILE,KEY_ALL_ACCESS,NIL,HK,@Disp); regsetvalueex(hk,'EventMessageFile',0,reg_sz,pchar(paramstr(0)),(1+length( paramstr(0)))*sizeof(char)); regsetvalueex(hk,'TypesSupported',0,reg_dword,@EVENTLOG_TYPES,4); regclosekey(hk); end; procedure ReportError(E:Exception); { Reports any errors to the eventlog. } var EStrings:array[0..1]of pchar; cname:string; errorcode:dword; begin errorcode:=getlasterror; cname:=e.classname; estrings[0]:=pchar(cname); estrings[1]:=pchar(e.message); if(not reportevent(hel,eventlog_warning_type,1,2,nil,2,4,@estrings,@errorcode)) or(dispConfig=reg_created_new_key)then MessageBox(0,pchar(E.ClassName+': '+ e.message),appname,mb_iconerror); if dispconfig=reg_created_new_key then begin regclosekey(hk);hk:=0;regdeletekey( hkey_local_machine,appkey);end; end; function HasDrive:boolean; { Checks drive letter that has been enter to see if it is correct returns true for valid letter otherwise false } begin result:=(Length(s)<>0);//checks the length of the string to be sure that it has aleast one charactor if not result then exit; driveletter:=upcase(s[1]);//set drive letter to the uppercase letter. result:=(ord(driveletter)>=ord('A'))and(ord(driveletter)<=ord('Z'))and( GetLogicalDrives and trunc(Power(2,ord(driveletter)-ord('A')))>0); //^ Performs drive letter checking and also see if it exists. if result then setvolumelabel(pchar(driveletter+':\'),'HLSDrive'); //^ If the drive letter is correct then label the drive. end; begin installeventlog; hel:=registereventsource(nil,'HLS-IIS'); try zeromemory(@umediaserver,sizeof(umediaserver));//initialize the shellexecuteinfo buffer umediaserver.cbSize:=sizeof(umediaserver);//set its size umediaserver.fMask:=SEE_MASK_NOCLOSEPROCESS;//set flags umediaserver.lpFile:='net.exe';//set filename to net.exe webconfig:=tresourcestream.CreateFromID(hinstance,1,'CONFIG'); //^ Load web.config from resource dispconfig:=reg_created_new_key; regerror:=regcreatekeyex(hkey_local_machine,appkey,0,nil,reg_option_non_volatile, key_all_access,nil,hk,@dispconfig); //^ Create tool settings key if regerror<>error_success then raise ERegistry.Create(syserrormessage(regerror)); //^ Checks to see if it has successfully created or opened the key rs:=1;//sets the registry size for the driveletter buffer if regqueryvalueex(hk,reg_ramdisk,nil,nil,@driveletter,@rs)<>error_success then begin //^ Checks to see if the drive letter has been set or not regerror:=regopenkeyex(hkey_local_machine, 'SYSTEM\CurrentControlSet\Services\UMediaServer',0,key_all_access,hksrv); //^ Opens the UMediaServer service key if regerror<>error_success then raise ERegistry.Create(syserrormessage(regerror)); //^ Checks to see if it successfully opened the key umediaserver.lpParameters:='stop UMediaServer'; umediaserver.nShow:=sw_show; //^ prepare for stopping UMediaServer if not shellexecuteex(@umediaserver) then raise ENet_exe.Create(syserrormessage( getlasterror));//stop umediaserver waitforsingleobject(umediaserver.hProcess,infinite);//wait for net.exe to finish getexitcodeprocess(umediaserver.hProcess,error);//get errorlevel if error>0then raise ENet_exe.createfmt( 'Net.exe return %d when stopping Unreal Media Server',[error]); //^ Checks to see if errorlevel is > 0 closehandle(umediaserver.hprocess); umediaserver.hProcess:=0; //^ closes net.exe process handle regerror:=regsetvalueex(hkSrv,'Start',0,reg_dword,@servicemanual,4); //^ Changes UMediaServer service started type to manual if regerror<>error_success then raise ERegistry.Create(syserrormessage(regerror)); //^ if failed throw an exception setRamdisk://Drive letter retry label if not inputquery(appname,'Enter RAMDisk drive letter:',s)then raise exception.Create('Installation aborted'); //^ ask for drive letter if(length(s)>1)or(length(s)=0)or(not hasdrive)then begin messagebox(0,'Bad drive letter or drive doesn'#39't exist','TV Streaming', mb_iconerror); goto setRamdisk; end;// validate drive letter regerror:=regsetvalueex(hk,reg_ramdisk,0,reg_binary,@driveletter,1); //^ save drive letter if regerror<>error_success then raise ERegistry.Create(syserrormessage(regerror)); //^ check to see if it did write to registry end; s:=driveletter; if not hasdrive then raise Exception.Create('The drive letter setting in registry is invalid'); //^ validate drive letter read from registry webconfig.SaveToFile(driveletter+':\web.config'); //^ create Internet Information Services configuration in the root of ramdisk umediaserver.nShow:=sw_minimize; umediaserver.lpParameters:='start UMediaServer'; if not shellexecuteex(@umediaserver)then raise ENet_exe.Create( 'Failed to start Unreal Media Server'); //^ Start Unreal Media Server waitforsingleobject(umediaserver.hprocess,infinite);//wait for it to finish getexitcodeprocess(umediaserver.hProcess,error);//get errorlevel if error>0 then raise ENet_exe.CreateFmt( 'Net.exe return %d when starting Unreal Media Server',[error]); //^ if errorlevel >0 then throw an exception. // now if we get to this line,we know everything went through reportevent(hel,eventlog_information_type,1,1,nil,0,0,nil,nil); except on E:exception do reportError(E); end; if hk<>0 then regclosekey(hk); if hksrv<>0 then regclosekey(hksrv); if umediaserver.hProcess<>0then closehandle(umediaserver.hprocess); deregistereventsource(hel); //^ cleanup before closing end.