B4A Library [B4X] [class] MJPEG decoder

The attached class is an implementation of a MJPEG over Http decoder.

The data is a mix of strings and raw bytes.
It is tempting to convert the bytes to a string. However raw bytes do not represent a valid string so you can lose important information during the conversion (which will also slow down the program).

Edit: For new projects it is recommended to use BytesBuilder.

The following sub is used to search for strings or bytes in the raw bytes directly:
B4X:
Private Sub IndexOfString(s As String, Start As Int) As Int
   Return IndexOf(s.GetBytes("ASCII"), Start)
End Sub

Private Sub IndexOf(bs() As Byte, Start As Int) As Int
   For i = Start To index - 1 - bs.Length
     For b = 0 To bs.Length - 1
       If bs(b) <> Data(i + b) Then Exit
     Next
     If b = bs.Length Then Return i
   Next
   Return -1
End Sub

The data is copied to a large array. Once a frame is found it is parsed and the array is trimmed using ByteConverter.ArrayCopy.

It is compatible with B4i, B4A and B4J.

upload_2016-12-1_18-18-56.png
SS-2016-12-01_18.19.30.jpg


SS-2016-12-01_18.32.05.jpg


It works better in release mode.
You will need to handle disconnections.
 

Attachments

  • MJPEG.zip
    4.2 KB · Views: 1,503
Last edited:

adrianfreitas

Member
Licensed User
Longtime User
hum... I see... great lesson here, the data management is a bit more complex. My approach was translate it directly, a lack of knowledge, for sure.
Thank you one more time, Erel,
 

inakigarm

Well-Known Member
Licensed User
Longtime User
Changes for B4J: change bitmap object (B4A) to image (B4J) in Main code and Module (in AStream_NewSata Sub on MJPEG.BAS Module)

B4X:
#Region Project Attributes
    #MainFormWidth: 600
    #MainFormHeight: 400
#End Region

Sub Process_Globals
    Private fx As JFX
    Private MainForm As Form
    Private Imgmjpeg As ImageView
    Public mjpeg1 As MJPEG
End Sub

Sub AppStart (Form1 As Form, Args() As String)
    MainForm = Form1
    MainForm.RootPane.LoadLayout("lyprojmjpeg") 'Load the layout file.
    MainForm.Show
    mjpeg1.Initialize(Me, "mjpeg")
    mjpeg1.Connect("195.113.207.238", 80)
End Sub

Public Sub mjpeg_Frame(img As Image)
    Imgmjpeg.SetImage(img)
End Sub

B4X:
'                Dim bmp As Bitmap
'                bmp.Initialize2(In)
'                CallSub2(mCallback, mEventName & "_frame", bmp)
                Dim img As Image
                img.Initialize2(In)
                CallSub2(mCallback, mEventName & "_frame", img)

upload_2016-12-2_9-30-17.png
 

inakigarm

Well-Known Member
Licensed User
Longtime User
Ok thanks, that's because I've downloaded only MJPEG.zip and modified the .Bas included on it (that doesn't include conditional compilation)
 

adrianfreitas

Member
Licensed User
Longtime User
Writing my app, I realized that it does not working with other cameras. The IPs below, for example, work in both the browser and the implementations in VB6 and Xojo, but they are not working with this class. I tried some variations but it did not work out.
Here are some IP's that did not work:

96.249.39.25 (96.249.39.25/mjpg/video.mjpg)
80.147.29.25 (80.147.29.25/mjpg/video.mjpg)
66.175.76.125 (66.175.76.125/axis-cgi/mjpg/video.cgi?resolution=640x480)
 

adrianfreitas

Member
Licensed User
Longtime User
Excelent as always!!
By the way, I didn't know this syntax:
B4X:
$"GET ${mPath} HTTP/1.1
            Host: ${mHost}
            Connection: keep-alive
            "$

One more learned... Thank you!
 

tchart

Well-Known Member
Licensed User
Longtime User
My security camera requires a user name and password. I cant see any way to pass this to the socket.

Has anyone tried this with secure cameras?
 

tchart

Well-Known Member
Licensed User
Longtime User
Actually figured it out. You need to add this to the header;

B4X:
Dim sTmp As String = $"GET ${mPath} HTTP/1.1
Host: ${mHost}
Authorization:Basic ${Token}
Connection: keep-alive
"$

The token is a base64 encryption of username:password like this;

B4X:
Dim YOUR_USERNAME As String = "admin"
Dim YOUR_PASSWORD As String = "mypassword"   
Dim Token As String

Dim Temp As String = YOUR_USERNAME & ":" & YOUR_PASSWORD
Dim TempBytes() As Byte = Temp.GetBytes("UTF8")   
Token = su.EncodeBase64(TempBytes)
 
Top