patch H264 RTP support and some other

For questions and discussion that is NOT (I repeat NOT) specific to a certain Operating System.
vitalyvb

patch H264 RTP support and some other

Postby vitalyvb » 13 Apr 2006 15:12

Sorry if it's a wrong place to send a patch but looks like vlc-devel mail server really hates me - I can't post anything there even subscribed...

I'm using VLC as a RTP/RTSP VOD server and I hope this patch or some parts will be useful for VLC project.

1. H.264 RTP packetizer.

It works fine for streaming video to a VLC Client but QuickTime do not
recognizes the stream. I.e. it plays only a sound and no video. There's also
no "H264" in "Stream Info" page, only audio (AAC in my case). I believe it's a
SDP issue - some parameters are missing.

2. Show client IP and port numbers in telnet's "show" command output.

Like this:
ondemandstream
type : vod
enabled : yes
instances
1375840326 : playing
address : 172.16.1.173:6970/6972

3. Seekable VOD.

It's not perfect but is better than nothing, imho. Particularly, it do not
works (don't know why) if stream is seeked with "dragging" current position
pointer and player tries to play lively seeked position.

4. Stop sending UDP stream if there are errors (e.g. "icmp port unreachable")

It's very useful feature for VOD (if client dies then transmission stops) but
(I've just realized) will probably break current #udp{} setups, so it should
be optional 8)

Code: Select all

Index: src/misc/vlm.c =================================================================== --- src/misc/vlm.c (revision 15183) +++ src/misc/vlm.c (working copy) @@ -1308,6 +1308,12 @@ return VLC_SUCCESS; } + else if( !strcmp( psz_command, "setclientid" ) ) + { + var_Create( p_instance->p_input, "clientid", VLC_VAR_STRING ); + var_SetString( p_instance->p_input, "clientid", psz_args ); + return VLC_SUCCESS; + } return VLC_EGENERIC; } @@ -1867,18 +1873,30 @@ for( j = 0; j < m->i_instance; j++ ) { + vlm_message_t *msg_iinfo; vlm_media_instance_t *p_instance = m->instance[j]; vlc_value_t val; if( !p_instance->p_input ) val.i_int = END_S; else var_Get( p_instance->p_input, "state", &val ); - vlm_MessageAdd( msg_instance, + msg_iinfo = vlm_MessageAdd( msg_instance, vlm_MessageNew( p_instance->psz_name ? p_instance->psz_name : "default", val.i_int == PLAYING_S ? "playing" : val.i_int == PAUSE_S ? "paused" : "stopped" ) ); + + val.psz_string = NULL; + if( p_instance->p_input ){ + var_Get( p_instance->p_input, "clientid", &val ); + } + + if (val.psz_string){ + vlm_MessageAdd( msg_iinfo, vlm_MessageNew( "address", + "%s", val.psz_string ) ); + } + } } @@ -2353,6 +2371,13 @@ break; } + case VOD_MEDIA_SETCLIENTID: + { + char *clid = (char*)va_arg( args, char* ); + i_ret = vlm_MediaControl( vlm, vlm->media[i], psz_id, "setclientid", clid); + break; + } + default: break; } Index: modules/access_output/udp.c =================================================================== --- modules/access_output/udp.c (revision 15183) +++ modules/access_output/udp.c (working copy) @@ -338,6 +338,18 @@ { sout_access_out_sys_t *p_sys = p_access->p_sys; + if ( p_sys->p_thread->b_error != 0 ){ + while( p_buffer ){ + block_t *p_next; + + p_next = p_buffer->p_next; + block_Release( p_buffer ); + p_buffer = p_next; + } + + return -1; + } + while( p_buffer ) { block_t *p_next; @@ -420,6 +432,19 @@ sout_access_out_sys_t *p_sys = p_access->p_sys; block_t *p_buf; + if ( p_sys->p_thread->b_error != 0 ){ + while( p_buffer ){ + block_t *p_next; + + p_next = p_buffer->p_next; + block_Release( p_buffer ); + p_buffer = p_next; + } + + return -1; + } + + while ( p_sys->p_thread->p_empty_blocks->i_depth >= MAX_EMPTY_BLOCKS ) { p_buf = block_FifoGet(p_sys->p_thread->p_empty_blocks); @@ -505,6 +530,8 @@ mtime_t i_date_last = -1; mtime_t i_to_send = p_thread->i_group; int i_dropped_packets = 0; + int i_send_err_count = 0; + mtime_t i_last_send_err = -1; #if defined(WIN32) || defined(UNDER_CE) char strerror_buf[WINSOCK_STRERROR_SIZE]; # define strerror( x ) winsock_strerror( strerror_buf ) @@ -522,9 +549,9 @@ while( p_tmp ) { p_tmp = p_tmp->p_next; i++;} p_tmp = p_thread->p_fifo->p_first; while( p_tmp ) { p_tmp = p_tmp->p_next; j++;} - msg_Err( p_thread, "fifo depth: %d/%d, empty blocks: %d/%d", + msg_Err( p_thread, "fifo depth: %d/%d, empty blocks: %d/%d", p_thread->p_fifo->i_depth, j,p_thread->p_empty_blocks->i_depth,i ); - } + } #endif p_pk = block_FifoGet( p_thread->p_fifo ); @@ -557,10 +584,23 @@ mwait( i_date ); i_to_send = p_thread->i_group; } + if( send( p_thread->i_handle, p_pk->p_buffer, p_pk->i_buffer, 0 ) == -1 ) { - msg_Warn( p_thread, "send error: %s", strerror(errno) ); + msg_Warn( p_thread, "send error#%d: %s", i_send_err_count, strerror(errno) ); + i_send_err_count ++; + i_last_send_err = i_date; + } else { + if ( i_send_err_count > 0 ) + { + if ( (i_last_send_err - i_date) > 1000000 ) + { + i_send_err_count -= 5; + if ( i_send_err_count < 0 ) + i_send_err_count = 0; + } + } } if( i_dropped_packets ) @@ -578,6 +618,12 @@ } #endif + if (i_send_err_count > 50){ + msg_Warn( p_thread, "too many send errors. stopping." ); + p_thread->b_error = 1; + p_thread->b_die = 1; + } + block_FifoPut( p_thread->p_empty_blocks, p_pk ); i_date_last = i_date; Index: modules/stream_out/rtp.c =================================================================== --- modules/stream_out/rtp.c (revision 15183) +++ modules/stream_out/rtp.c (working copy) @@ -902,6 +902,7 @@ static int rtp_packetize_mp4a ( sout_stream_t *, sout_stream_id_t *, block_t * ); static int rtp_packetize_mp4a_latm ( sout_stream_t *, sout_stream_id_t *, block_t * ); static int rtp_packetize_h263 ( sout_stream_t *, sout_stream_id_t *, block_t * ); +static int rtp_packetize_h264 ( sout_stream_t *, sout_stream_id_t *, block_t * ); static int rtp_packetize_amr ( sout_stream_t *, sout_stream_id_t *, block_t * ); static void sprintf_hexa( char *s, uint8_t *p_data, int i_data ) @@ -1067,6 +1068,12 @@ id->psz_rtpmap = strdup( "H263-1998/90000" ); id->pf_packetize = rtp_packetize_h263; break; + case VLC_FOURCC( 'h', '2', '6', '4' ): + id->i_payload_type = p_sys->i_payload_type++; + id->i_clock_rate = 90000; + id->psz_rtpmap = strdup( "H264/90000" ); + id->pf_packetize = rtp_packetize_h264; + break; case VLC_FOURCC( 'm', 'p', '4', 'v' ): { @@ -2335,6 +2342,130 @@ return VLC_SUCCESS; } +/* rfc3984 */ +static int rtp_packetize_h264( sout_stream_t *p_stream, sout_stream_id_t *id, + block_t *in ) +{ + int i_max = id->i_mtu - 12; /* payload max in one packet */ + int i_count = ( in->i_buffer + i_max - 1 ) / i_max; + uint8_t *p_data = in->p_buffer; + int i_data = in->i_buffer; + int i; + + + if (i_data <= i_max) { + /* NAL */ + int i_payload; + block_t *out; + uint8_t *p = p_data; + int i_rest = in->i_buffer; + + while( i_rest > 4 && + ( p[0] != 0x00 || p[1] != 0x00 || p[2] != 0x01 ) ) + { + p++; + i_rest--; + } + + if (i_rest < 4) + return VLC_SUCCESS; + + p+=3; + i_rest-=3; + + i_payload = __MIN( i_max, i_rest ); + out = block_New( p_stream, 12 + i_payload ); + + /* rtp common header */ + rtp_packetize_common( id, out, 1, + in->i_pts > 0 ? in->i_pts : in->i_dts ); + + memcpy( &out->p_buffer[12], p, i_payload ); + + out->i_buffer = 12 + i_payload; + out->i_dts = in->i_dts; + out->i_length = in->i_length; + + rtp_packetize_send( id, out ); + + /*msg_Dbg( p_stream, "nal-out plain %d %02x", i_payload, out->p_buffer[16] );*/ + + } else { + /* FU-A */ + int i_payload; + block_t *out; + uint8_t *p = p_data; + int i_rest = in->i_buffer; + int start=1, end=0, first=0, nalh=-1; + + while( i_rest > 4 && + ( p[0] != 0x00 || p[1] != 0x00 || p[2] != 0x01 ) ) + { + p++; + i_rest--; + } + + if (i_rest < 4) + return VLC_SUCCESS; + + p+=3; + i_rest-=3; + + nalh = *p; + + p++; + i_rest--; + + i_max = id->i_mtu - 14; + i_count = ( i_rest + i_max - 1 ) / i_max; + + + /*msg_Dbg( p_stream, "nal-out fragmented %02x %d", nalh, i_rest);*/ + + i=0; + while (end==0){ + i_payload = __MIN( i_max, i_rest ); + out = block_New( p_stream, 14 + i_payload ); + + if (i_rest==i_payload) + end = 1; + + /* rtp common header */ + rtp_packetize_common( id, out, (end)?1:0, + in->i_pts > 0 ? in->i_pts : in->i_dts ); + + /* FU indicator */ + out->p_buffer[12] = (nalh&0x60)|28; + /* FU header */ + out->p_buffer[13] = (start<<7)|(end<<6)|(nalh&0x1f); + + memcpy( &out->p_buffer[14], p+first, i_payload ); + + out->i_buffer = 14 + i_payload; + + // not sure what of these should be used and what it does :) + //out->i_dts = in->i_dts + i * in->i_length / i_count; + //out->i_length = in->i_length / i_count; + out->i_dts = in->i_dts; + out->i_length = in->i_length; + + rtp_packetize_send( id, out ); + + /*msg_Dbg( p_stream, "nal-out fragmented: frag %d %d %02x %02x %d", start,end, + out->p_buffer[12], out->p_buffer[13], i_payload );*/ + + i_rest -= i_payload; + first += i_payload; + i++; + start=0; + } + + } + + return VLC_SUCCESS; +} + + static int rtp_packetize_amr( sout_stream_t *p_stream, sout_stream_id_t *id, block_t *in ) { Index: modules/misc/rtsp.c =================================================================== --- modules/misc/rtsp.c (revision 15183) +++ modules/misc/rtsp.c (working copy) @@ -125,6 +125,7 @@ char *psz_rtsp_control_v6; char *psz_rtsp_path; + char *psz_client_ip; int i_port; int i_port_audio; int i_port_video; @@ -353,6 +354,8 @@ } vlc_mutex_unlock( &p_item->lock ); + p_media->psz_client_ip = NULL; + return p_media; } @@ -377,6 +380,9 @@ free( p_media->psz_session_description ); free( p_media->psz_session_url ); free( p_media->psz_session_email ); + + if (p_media->psz_client_ip) + free( p_media->psz_client_ip ); free( p_media ); } @@ -434,6 +440,12 @@ p_es->i_payload_type = p_media->i_payload_type++; p_es->psz_rtpmap = strdup( "H263-1998/90000" ); break; + case VLC_FOURCC( 'h', '2', '6', '4' ): + p_es->i_payload_type = p_media->i_payload_type++; + p_es->psz_rtpmap = strdup( "H264/90000" ); + p_es->psz_fmtp = strdup("packetization-mode=1"); + + break; case VLC_FOURCC( 'm', 'p', '4', 'v' ): p_es->i_payload_type = p_media->i_payload_type++; p_es->psz_rtpmap = strdup( "MP4V-ES/90000" ); @@ -767,6 +779,9 @@ { char *psz_output, ip[NI_MAXNUMERICHOST]; int i, i_port_audio = 0, i_port_video = 0; + int port1 = 0, port2 = 0; + char *psz_clid = NULL, *psz_position = NULL; + double f_seek_pos = -1.0; /* for now only multicast so easy */ if( !psz_playnow ) @@ -781,13 +796,46 @@ psz_session = httpd_MsgGet( query, "Session" ); msg_Dbg( p_vod, "HTTPD_MSG_PLAY for session: %s", psz_session ); + psz_position = httpd_MsgGet( query, "Range" ); + if( psz_position ) psz_position = strstr( psz_position, "npt=" ); + + if (psz_position){ + char *end; + + msg_Dbg( p_vod, "seeking request: %s", psz_position ); + + psz_position += 4; + + /* FIXME: npt= is not necessarily formatted as a float */ + f_seek_pos = us_strtod( psz_position, &end ); + } + p_rtsp = RtspClientGet( p_media, psz_session ); if( !p_rtsp ) break; + if(p_rtsp->b_playing && (f_seek_pos >= 0.0)){ + if(p_rtsp->b_paused == VLC_FALSE) + { + vod_MediaControl( p_vod, p_media, psz_session, + VOD_MEDIA_PAUSE ); + + p_rtsp->b_paused = VLC_TRUE; + } + } + if( p_rtsp->b_playing && p_rtsp->b_paused ) { + + if(f_seek_pos > 0.0) + { + f_seek_pos /= ((double)(p_media->i_length))/1000 /1000 / 100; + vod_MediaControl( p_vod, p_media, psz_session, + VOD_MEDIA_SEEK, f_seek_pos ); + } + vod_MediaControl( p_vod, p_media, psz_session, VOD_MEDIA_PAUSE ); + p_rtsp->b_paused = VLC_FALSE; break; } @@ -806,27 +854,40 @@ i_port_video = p_rtsp->es[i]->i_port; } + if( p_media->psz_mux ) { if( p_media->b_raw ) { asprintf( &psz_output, "std{access=udp,dst=%s:%i,mux=%s}", ip, i_port, p_media->psz_mux ); + port1 = i_port; } else { asprintf( &psz_output, "rtp{dst=%s,port=%i,mux=%s}", ip, i_port_video, p_media->psz_mux ); + port1 = i_port_video; } } else { asprintf( &psz_output, "rtp{dst=%s,port-video=%i," "port-audio=%i}", ip, i_port_video, i_port_audio ); + port1 = i_port_video; + port2 = i_port_audio; } vod_MediaControl( p_vod, p_media, psz_session, VOD_MEDIA_PLAY, psz_output ); + + if ( p_media->psz_client_ip ) + free( p_media->psz_client_ip ); + asprintf(&psz_clid, "%s:%d/%d", ip, port1, port2); + p_media->psz_client_ip = psz_clid; + vod_MediaControl( p_vod, p_media, psz_session, + VOD_MEDIA_SETCLIENTID, p_media->psz_client_ip ); + free( psz_output ); break; } Index: include/vlc_vod.h =================================================================== --- include/vlc_vod.h (revision 15183) +++ include/vlc_vod.h (working copy) @@ -63,6 +63,7 @@ VOD_MEDIA_PAUSE, /* arg1= double * res= */ VOD_MEDIA_STOP, /* arg1= double res=can fail */ VOD_MEDIA_SEEK, /* arg1= double * res= */ + VOD_MEDIA_SETCLIENTID, }; #endif

Guest

Postby Guest » 31 Jul 2006 04:40

you did a greate job!!!!
I love you!!!
I was looking for a h264 packetize long time ago.

cue8chalk
New Cone
New Cone
Posts: 8
Joined: 01 Aug 2006 06:02

Postby cue8chalk » 01 Aug 2006 06:42

you did a greate job!!!!
I love you!!!
I was looking for a h264 packetize long time ago.
Does this work? Is there any chance of getting a new Windows binary compiled with h264 packetize support anytime soon?

The DJ
Cone Master
Cone Master
Posts: 5987
Joined: 22 Nov 2003 21:52
VLC version: git
Operating System: Mac OS X
Location: Enschede, Holland
Contact:

Postby The DJ » 01 Aug 2006 16:59

This code is already in VLC.
Don't use PMs for support questions.

cue8chalk
New Cone
New Cone
Posts: 8
Joined: 01 Aug 2006 06:02

Postby cue8chalk » 04 Aug 2006 22:07

This code is already in VLC.
Really? How come I can't seem to get it working. When I try to create an rtsp stream with VLC under windows, and I have the debug log open using H264/mp4a, I get errors saying "no packetizer" found. More specifically, here's my output in the debug log:

Code: Select all

[00000297] logger interface: VLC media player - version 0.8.5 Janus - (c) 1996-2 006 the VideoLAN team [00000297] logger interface: Warning: if you can't access the GUI anymore, open a command-line window, go to the directory where you installed VLC and run "vlc -I wx" [00000297] logger interface: using logger... [00000368] [Media: test] ffmpeg encoder error: cannot find encoder h264 [00000352] [Media: test] stream_out_transcode private error: cannot find encoder [00000352] [Media: test] stream_out_transcode private error: cannot create video chain [00000365] [Media: test] main packetizer error: cannot create packetizer output (mp4v)
... but I am able to transocde the video using the same settings (but not video-on-demand). Here's the output of that in the debug log:

Code: Select all

x264 [info]: using cpu capabilities MMX MMXEXT SSE SSE2 3DNow! x264 [info]: using SAR=44999/45000 x264 [info]: using cpu capabilities MMX MMXEXT SSE SSE2 3DNow! x264 [info]: slice I:11 Avg QP:25.73 size: 5017 x264 [info]: slice P:955 Avg QP:28.18 size: 606 x264 [info]: mb I I16..4: 19.8% 0.0% 80.2% x264 [info]: mb P I16..4: 0.3% 0.0% 0.7% P16..4: 35.1% 13.2% 4.6% 0.3% 0 .2% skip:45.7% x264 [info]: kb/s:125.8 [00000284] main playlist: nothing to play
I'm trying to create a rtsp stream that is playable in Quicktime. It seems I can create files, but am unable to get it working as a video-on-demand (rtsp) stream. Can anyone shed some light on this issue? Thanks!

Teetrinker
Cone that earned his stripes
Cone that earned his stripes
Posts: 174
Joined: 16 Aug 2004 16:12

Postby Teetrinker » 04 Aug 2006 22:15

Try it again with svn or a nightly build. As far as I know playback on client side is only working with VLC at the moment. See also here: viewtopic.php?t=24345

cue8chalk
New Cone
New Cone
Posts: 8
Joined: 01 Aug 2006 06:02

Postby cue8chalk » 04 Aug 2006 22:39

Try it again with svn or a nightly build. As far as I know playback on client side is only working with VLC at the moment. See also here: viewtopic.php?t=24345
Yeah, it doesn't seem to work yet. I get the same error messages in my debug console with the latest nightly as I did with 0.8.5. I am really looking forward to when this is working.

Teetrinker
Cone that earned his stripes
Cone that earned his stripes
Posts: 174
Joined: 16 Aug 2004 16:12

Postby Teetrinker » 04 Aug 2006 23:03

How does your vlc comand line look?

cue8chalk
New Cone
New Cone
Posts: 8
Joined: 01 Aug 2006 06:02

Postby cue8chalk » 04 Aug 2006 23:10

How does your vlc comand line look?
Actually, I used the web interface. I'm not that great at using vlc from the command line. Here's what my setup looks like from the vlm export:

Code: Select all

new test vod enabled setup test input "C:\Documents and Settings\...\Coming to America - Soup.avi" setup test output #transcode{vcodec=H264,vb=128,scale=1,acodec=mp4a,ab=128}:std{access=rtp,mux=mp4,dst=}
I'm not sure if my transcode settings are correct for it to be viewable in Quicktime, so any guidance is much appreciated!

By the way, I've tried wrpaping it in MPEG TS as well, and it still hasn't worked for me.

Teetrinker
Cone that earned his stripes
Cone that earned his stripes
Posts: 174
Joined: 16 Aug 2004 16:12

Postby Teetrinker » 05 Aug 2006 00:03

Don't use "mux=mp4" this isn't supported by vlc: http://www.videolan.org/streaming/features.html

Use only rtp with raw elementary streams.

Scale=1 may be to much for your CPU.

And you will probably need to run DSS at the same PC. If I didn't used DSS to relay the stream, I had problems to receave it on other computers.

If you use something like this you should be able to watch the stream with vlc:

vlc -vvv 'input.avi' --sout '#transcode{vcodec="h264",scale=0.5,vb="384",acodec="mp4a",ab="128",channels="2"}:rtp{dst="127.0.0.1",port-audio="22002",port-video="22000",ttl="15",sdp=file:///home/user/test.sdp,}'
Copy the sdp file in the movie directory from DSS. But playback will only work with VLC for the moment.

or
vlc -vvv 'input.avi' --sout '#transcode{vcodec="h264",scale=0.5,vb="384",acodec="mp4a",ab="128",channels="2"}:rtp{dst="127.0.0.1",port-audio="22002",port-video="22000",ttl="15",sdp=rtsp://yourIP/test.sdp,}'

At the moment I am back at VLC 0.8.5 because I had some trouble with DVB-S with the svn vlc version. So I hope I did no mistake with mentioned commandline.

I am not sure if you have to adjust the the x264 settings to be compatible with Quicktime. I wasn't able to decode the created stream with Osmo4 ( http://gpac.sf.net ). Other H.264 streams from DSS work fine with Osmo4 even if b-frames are used as references. VLC stutters with H.264 with b_pyramid last time I tested it.

cue8chalk
New Cone
New Cone
Posts: 8
Joined: 01 Aug 2006 06:02

Postby cue8chalk » 05 Aug 2006 00:10

Don't use "mux=mp4" this isn't supported by vlc: http://www.videolan.org/streaming/features.html

Use only rtp with raw elementary streams.

Scale=1 may be to much for your CPU.

And you will probably need to run DSS at the same PC. If I didn't used DSS to relay the stream, I had problems to receave it on other computers.

If you use something like this you should be able to watch the stream with vlc:

vlc -vvv 'input.avi' --sout '#transcode{vcodec="h264",scale=0.5,vb="384",acodec="mp4a",ab="128",channels="2"}:rtp{dst="127.0.0.1",port-audio="22002",port-video="22000",ttl="15",sdp=file:///home/user/test.sdp,}'
Copy the sdp file in the movie directory from DSS. But playback will only work with VLC for the moment.

or
vlc -vvv 'input.avi' --sout '#transcode{vcodec="h264",scale=0.5,vb="384",acodec="mp4a",ab="128",channels="2"}:rtp{dst="127.0.0.1",port-audio="22002",port-video="22000",ttl="15",sdp=rtsp://yourIP/test.sdp,}'

At the moment I am back at VLC 0.8.5 because I had some trouble with DVB-S with the svn vlc version. So I hope I did no mistake with mentioned commandline.

I am not sure if you have to adjust the the x264 settings to be compatible with Quicktime. I wasn't able to decode the created stream with Osmo4 ( http://gpac.sf.net ). Other H.264 streams from DSS work fine with Osmo4 even if b-frames are used as references. VLC stutters with H.264 with b_pyramid last time I tested it.
I'm getting ready to try this. I do need it to work with quicktime though. My aim is to stream a video to SecondLife (http://www.secondlife.com) and they use Quicktime as the video player. By the way, where can I get DSS?

Teetrinker
Cone that earned his stripes
Cone that earned his stripes
Posts: 174
Joined: 16 Aug 2004 16:12

Postby Teetrinker » 05 Aug 2006 00:13



Return to “General VLC media player Troubleshooting”

Who is online

Users browsing this forum: No registered users and 25 guests