Sending Jcodec H264 Encoded RTMP Message to Wowza - streaming

I am making screen share java based application. I am done with encoding frames into H264 using JCodec java Library. I have Picture data in Byte Buffer.
How I will send these encoded frames to Wowza through rtmp client?
Can Wowza recognize the H264 encoded frames, Encoded by Jcodec library?

Pretty much any of the "flash" media servers will understand h264 data in a stream. You'll need to encode your frames with baseline or main profile and then "package" the encoded bytes into flv streaming format. The first step is creating an AMF video data item, what that means is prefixing and suffixing the h264 encoded byte array based on its "NALU" content; in pseudo code it looks something like this:
if idr
flv[0] = 0x17 // 0x10 key frame; 0x07 h264 codec id
flv[1] = 0x01 // 0 sequence header; 1 nalu; 2 end of seq
flv[2] = 0 // pres offset
flv[3] = 0 // pres offset
flv[4] = 0 // pres offset
flv[5] = 0 // size
flv[6] = 0 // size cont
flv[7] = 0 // size cont
flv[8] = 0 // size cont
else if coded slice
flv[0] = 0x27
flv[1] = 0x01
flv[2] = 0 // pres offset
flv[3] = 0 // pres offset
flv[4] = 0 // pres offset
flv[5] = 0 // size
flv[6] = 0 // size cont
flv[7] = 0 // size cont
flv[8] = 0 // size cont
else if PPS or SPS
.... skipping this here as its really complicated, this is the h264/AVC configuration data
copy(encoded, 0, flv, 9, encoded.length)
flv[flv.length - 1] = 0
The next step is packaging the AMF video data into an RTMP message. I suggest that you look at flazr or one of the android rtmp libraries for details on this step.
I've got a small example project that takes raw encoded h264 and writes it to an flv here if you want to see how its done.

Related

Icecast2 Mountpoint Not Displaying

I am adding Icecast2 to my Raspberry PI and can not get the mountpoint to show in the admin.
Here is my darkice.cfg
[general]
duration = 0 # duration in s, 0 forever
bufferSecs = 1 # buffer, in seconds
reconnect = yes # reconnect if disconnected
[input]
device = dmic_sv # Soundcard device for the audio input
sampleRate = 44100 # sample rate 11025, 22050 or 44100
bitsPerSample = 16 # bits
channel = 2 # 2 = stereo
[icecast2-0]
bitrateMode = cbr # constant bit rate ('cbr' constant, 'abr' average)
#quality = 1.0 # 1.0 is best quality (use only with vbr)
format = mp3 # format. Choose 'vorbis' for OGG Vorbis
bitrate = 320 # bitrate
server = localhost # or IP
port = 8000 # port for IceCast2 access
password = raspberry # source password for the IceCast2 server
mountPoint = turntable.mp3 # mount point on the IceCast2 server .mp3 or .ogg
name = Turntable
highpass = 18
lowpass = 20000
description = Turntable
Help!

Live Stream (of some channel) Play through Roku Box

I were trying to join igmp live streaming and play it in roku box. But it didn't worked.
Is it that we can not join multicast streaming in Roku boxes ?
If it is possible to do via HLS, then what could be the solution ?
I tried the reference in github at link : https://github.com/thetrime/trimeplay/blob/master/source/trimeplay.brs
Please refer the another code I were using as reference :
function SetupJoin()
ssdpAddress = "239.60.60.7:6607"
ssdpPort = 6607
timeout = 300 * 60 * 1000
groupAddr = CreateObject("roSocketAddress")
groupAddr.setAddress(ssdpAddress)
groupAddr.setPort(ssdpPort)
listenAddr = CreateObject("roSocketAddress")
listenAddr.setPort(ssdpPort)
listenAddr.setAddress("0.0.0.0")
listen = CreateObject("roDatagramSocket")
listen.setReuseAddr(true)
listen.setAddress(listenAddr)
result = listen.joinGroup(groupAddr)
listen.setMessagePort(canvas.GetMessagePort())
listen.notifyReadable(true)
numResponses= Wait_SSDP(listen, timeout)
? "Result : " result
? "SSDP Listen got"; numResponses; " responses"
end function
function Wait_SSDP(socket as Object, timeout as Integer) as Integer
numResponses = 0
elapsed = CreateObject("roTimespan")
remaining = timeout - elapsed.totalMilliseconds()
while remaining > 0
msg = wait(remaining, socket.getMessagePort())
if type(msg)="roSocketEvent"
if socket.isReadable()
results = socket.receiveStr(255)
print "SSDP Listen gets from "; socket.getReceivedFromAddress().getAddress(); ":"
print results
numResponses = numResponses + 1
end if
else
exit while 'enter code here
end if
remaining = timeout - elapsed.totalMilliseconds()
end while
return numResponses
end function
I'm not going to say that what you are trying to do is completely impossible, but it is impractical.
You would have to do something sort of like this:
Use roStreamSockets to collect the UDP data and write it to tmp:/ as an h.264 video file, probably as HLS chunks, then point the video playback component at it via .m3u8 files you also write on the fly. This would have to be done in Brightscript. I'm not sure that Brightscript is fast enough to do this. I'm not saying it is impossible to do it, but Roku does not natively play multicast or other UDP video stream formats.
The only officially supported video formats for live broadcast are HLS and Microsoft Smooth.

ffmpeg API h264 encoded video does not play on all platforms

Edit: In the previous version I used a very old ffmpeg API. I now use the newest libraries. The problem has only changed slightly, from "Main" to "High".
I am using the ffmpeg C API to create a mp4 video in C++.
I want the resulting video to be of the profile "Constrained Baseline", so that the resulting video can be played on as much platforms as possible, especially mobile, but I get "High" profile every time, even though I hard coded the codec profile to be FF_PROFILE_H264_CONSTRAINED_BASELINE. As a result, the video does not play on all our testing platforms.
This is what "ffprobe video.mp4 -show_streams" tells about my video streams:
Metadata:
major_brand : isom
minor_version : 512
compatible_brands: isomiso2avc1mp41
creation_time : 1970-01-01 00:00:00
encoder : Lavf53.5.0
Duration: 00:00:13.20, start: 0.000000, bitrate: 553 kb/s
Stream #0:0(und): Video: h264 (Main) (avc1 / 0x31637661), yuv420p, 320x180,
424 kb/s, 15 fps, 15 tbr, 15 tbn, 30 tbc
Metadata:
creation_time : 1970-01-01 00:00:00
handler_name : VideoHandler
Stream #0:1(und): Audio: aac (mp4a / 0x6134706D), 44100 Hz, stereo, s16, 12
kb/s
Metadata:
creation_time : 1970-01-01 00:00:00
handler_name : SoundHandler
-------VIDEO STREAM--------
[STREAM]
index=0
codec_name=h264
codec_long_name=H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10
profile=High <-- This should be "Constrained Baseline"
codec_type=video
codec_time_base=1/30
codec_tag_string=avc1
codec_tag=0x31637661
width=320
height=180
has_b_frames=0
sample_aspect_ratio=N/A
display_aspect_ratio=N/A
pix_fmt=yuv420p
level=30
timecode=N/A
is_avc=1
nal_length_size=4
id=N/A
r_frame_rate=15/1
avg_frame_rate=15/1
time_base=1/15
start_time=0.000000
duration=13.200000
bit_rate=424252
nb_frames=198
nb_read_frames=N/A
nb_read_packets=N/A
TAG:creation_time=1970-01-01 00:00:00
TAG:language=und
TAG:handler_name=VideoHandler
[/STREAM]
-------AUDIO STREAM--------
[STREAM]
index=1
codec_name=aac
codec_long_name=Advanced Audio Coding
profile=unknown
codec_type=audio
codec_time_base=1/44100
codec_tag_string=mp4a
codec_tag=0x6134706d
sample_fmt=s16
sample_rate=44100
channels=2
bits_per_sample=0
id=N/A
r_frame_rate=0/0
avg_frame_rate=0/0
time_base=1/44100
start_time=0.000000
duration=13.165714
bit_rate=125301
nb_frames=567
nb_read_frames=N/A
nb_read_packets=N/A
TAG:creation_time=1970-01-01 00:00:00
TAG:language=und
TAG:handler_name=SoundHandler
[/STREAM]
This is the function I use to add a video stream. All the values that come from ptr-> are defined from outside, do those values have to be specific values to get the correct profile?:
static AVStream *add_video_stream( Cffmpeg_dll * ptr, AVFormatContext *oc, enum CodecID codec_id )
{
AVCodecContext *c;
AVStream *st;
AVCodec* codec;
// Get correct codec
codec = avcodec_find_encoder(codec_id);
if (!codec) {
av_log(NULL, AV_LOG_ERROR, "%s","Video codec not found\n");
exit(1);
}
// Create stream
st = avformat_new_stream(oc, codec);
if (!st) {
av_log(NULL, AV_LOG_ERROR, "%s","Could not alloc stream\n");
exit(1);
}
c = st->codec;
/* Get default values */
codec = avcodec_find_encoder(codec_id);
if (!codec) {
av_log(NULL, AV_LOG_ERROR, "%s","Video codec not found (default values)\n");
exit(1);
}
avcodec_get_context_defaults3(c, codec);
c->codec_id = codec_id;
c->codec_type = AVMEDIA_TYPE_VIDEO;
c->bit_rate = ptr->video_bit_rate;
av_log(NULL, AV_LOG_ERROR, " Bit rate: %i", c->bit_rate);
c->qmin = ptr->qmin;
c->qmax = ptr->qmax;
c->me_method = ptr->me_method;
c->me_subpel_quality = ptr->me_subpel_quality;
c->i_quant_factor = ptr->i_quant_factor;
c->qcompress = ptr->qcompress;
c->max_qdiff = ptr->max_qdiff;
// We need to set the level and profile to get videos that play (hopefully) on all platforms
c->level = 30;
c->profile = FF_PROFILE_H264_CONSTRAINED_BASELINE;
c->width = ptr->dstWidth;
c->height = ptr->dstHeight;
c->time_base.den = ptr->fps;
c->time_base.num = 1;
c->gop_size = ptr->fps;
c->pix_fmt = STREAM_PIX_FMT;
c->max_b_frames = 0;
// some formats want stream headers to be separate
if(oc->oformat->flags & AVFMT_GLOBALHEADER)
c->flags |= CODEC_FLAG_GLOBAL_HEADER;
return st;
}
Additional info:
As a reference video, I use the gizmo.mp4 that Mozilla serves as an example that plays on every platform/browser. It definitely has the "Constrained Baseline" profile, and definitely works on all our testing smartphones. You can download it here. Our self-created video doesn't work on all platforms and I'm convinced this is because of the profile.
I am also using qt-faststart.exe to move the headers to the start of the file after creating the mp4, as this cannot be done in a good way in C++ directly. Could that be the problem?
Obviously, I am doing something wrong, but I don't know what it could be. I'd be thankful for every hint ;)
I have the solution. After spending some time and discussions in the ffmpeg bug tracker and browsing for profile setting examples, I finally figured out the solution.
One needs to use av_opt_set(codecContext->priv_data, "profile", "baseline" (or any other desired profile), AV_OPT_SEARCH_CHILDREN)
So in my case that would be:
Wrong:
// We need to set the level and profile to get videos that play (hopefully) on all platforms
c->level = 30;
c->profile = FF_PROFILE_H264_CONSTRAINED_BASELINE;
Correct:
// Set profile to baseline
av_opt_set(c->priv_data, "profile", "baseline", AV_OPT_SEARCH_CHILDREN);
Completely unintuitive and contrary to the rest of the API usage, but that's ffmpeg philosophy. You don't need to understand it, you just need to understand how to use it ;)

Add kAudioUnitSubType_Varispeed to AUGraph in iOS5

I am trying to add a kAudioUnitSubType to an AUGraph in iOS 5 but when I add it and call AUGraphInitialize an error code -10868 is returned (kAudioUnitErr_FormatNotSupported).
Here is my AudioComponentDescription:
AudioComponentDescription varispeedDescription;
varispeedDescription.componentType = kAudioUnitType_FormatConverter;
varispeedDescription.componentSubType = kAudioUnitSubType_Varispeed;
varispeedDescription.componentManufacturer = kAudioUnitManufacturer_Apple;
varispeedDescription.componentFlags = 0;
varispeedDescription.componentFlagsMask = 0;
If I print the state of the graph right before I initialise the graph I get the following:
AudioUnitGraph 0x918000:
Member Nodes:
node 1: 'auou' 'rioc' 'appl', instance 0x16dba0 O
node 2: 'aumx' 'mcmx' 'appl', instance 0x1926f0 O
node 3: 'aufc' 'vari' 'appl', instance 0x193b00 O
Connections:
node 2 bus 0 => node 3 bus 0 [ 2 ch, 44100 Hz, 'lpcm' (0x00000C2C) 8.24-bit little-endian signed integer, deinterleaved]
node 3 bus 0 => node 1 bus 0 [ 2 ch, 0 Hz, 'lpcm' (0x00000029) 32-bit little-endian float, deinterleaved]
Input Callbacks:
{0x39a5, 0x172e24} => node 2 bus 0 [2 ch, 44100 Hz]
{0x39a5, 0x172e24} => node 2 bus 1 [2 ch, 44100 Hz]
CurrentState:
mLastUpdateError=0, eventsToProcess=F, isRunning=F
As you can see the connection from the Varispeed unit to the Remote IO unit shows a very strange format. What is even more odd is that if I run this on the simulator as opposed to on my development device the format that shows is 16-bit little endian integer, deinterleaved. If I try to set the stream format on the input or output scopes of the Varispeed unit I get the same error code -10868.
The asbd that I am setting as the stream format on each Multichannel mixer bus on the input scope is as follows:
stereoFormat.mSampleRate = sampleRate;
stereoFormat.mFormatID = kAudioFormatLinearPCM;
stereoFormat.mFormatFlags = kAudioFormatFlagsCanonical;
stereoFormat.mFramesPerPacket = 1;
stereoFormat.mChannelsPerFrame = 2;
stereoFormat.mBitsPerChannel = 16;
stereoFormat.mBytesPerPacket = 4;
stereoFormat.mBytesPerFrame = 4;
The reason I am not using the canonical format for audio units is because I am reading samples from an AVAssetReader which I cannot configure to output 8.24 Signed Integer samples.
If I take out the Varispeed unit from the graph and connect the Multichannel Mixer unit to the input of the Remote IO unit the graph initialises and plays fine. Any idea what I'm doing wrong?
your io unit is asking for 32bit float and recieving 8.24 from the varispeed unit, hence the format error.
you can set the stream format on the output of varispeed to match the input format of the io unit like this:
AudioStreamBasicDescription asbd;
UInt32 asbdSize = sizeof (asbd);
memset (&asbd, 0, sizeof (asbd));
AudioUnitGetProperty(ioaudiounit , kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &asbd, &asbdSize);
AudioUnitSetProperty(varipseedaudiounit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 0, &asbd, sizeof(asbd));

How to remove header of a wavfile in Matlab

I need to remove first 1024 bytes of a wave file. I tried to do but I got corrupted/distorted wavfile:
wavFile = fopen(fullFileName, 'r'); % Open file for reading
fseek (wavFile, 1024, -1);% Skip past header, which is 1024 bytes long.
wF = fread (wavFile, inf, 'int16');% 16-bit signed integers
wF = wF(:)';
newWavFile = fopen(strcat('new_',fileNames(fileNo).name), 'w+');% Open file for reading
fwrite(newWavFile,wF);
fclose(wavFile);
What can be the problem?
I could manage to remove header and correct the distortion by :
wavFile = fopen(fullFileName, 'r');% Open file for reading
fseek (wavFile, 1024, -1);% Skip past header, which is 1024 bytes long.
wF = fread (wavFile, inf, 'int16');% 16-bit signed integers
wF = wF(:)';
wF = 0.8*wF/max(abs(wF));
newWavFile =strcat('1_',fileNames(fileNo).name);% Open file for reading
wavwrite(wF,16000,16,newWavFile);