Android Question Help needed for MJPEG

HARRY

Active Member
Licensed User
Longtime User
Hi,

I am trying to display a MJPEG stream on my Android phone using the MJPEG B4J example. I have adapted this example to B4A and my needs, just one stream. The stream displays perfectly in a web browser, but I don't get it running on my phone. The connection is made, but no image is shown.

My code at this moment is for Main :

B4X:
#Region  Project Attributes
    #ApplicationLabel: B4A Example
    #VersionCode: 1
    #VersionName:
    'SupportedOrientations possible values: unspecified, landscape or portrait.
    #SupportedOrientations: unspecified
    #CanInstallToExternalStorage: False
#End Region
#Region  Activity Attributes
    #FullScreen: False
    #IncludeTitle: True
#End Region

Sub Process_Globals
    'These global variables will be declared once when the application starts.
    'These variables can be accessed from all modules.
    Private mj1 As MJPEG
    
End Sub

Sub Globals
    'These global variables will be redeclared each time the activity is created.
    'These variables can only be accessed from this module.
    Private ImageView1 As ImageView
    
End Sub

Sub Activity_Create(FirstTime As Boolean)
    'Do not forget to load the layout file created with the visual designer. For example:
    'Activity.LoadLayout("Layout1")
    Activity.LoadLayout("1")   
    mj1.Initialize(Me, "mj1")
    mj1.Connect("192.168.2.4/",8000)
End Sub

Sub Activity_Resume

End Sub

Sub Activity_Pause (UserClosed As Boolean)

End Sub

Sub mj1_Frame(bmp As Bitmap)
    ImageView1.SetBackgroundImage(bmp)
End Sub

and for MJPEG:

B4X:
Sub Class_Globals
    Private sock As Socket
    Private Astream As AsyncStreams
    Private mCallback As Object
    Private mEventName As String
    Private mHost As String
    Private mPath As String
    Private Data(1000000) As Byte
    Private index As Int
    Private bc As ByteConverter
    Private boundary As String
End Sub

Public Sub Initialize (Callback As Object, EventName As String)
    mCallback = Callback
    mEventName = EventName
End Sub

Public Sub Connect(url As String, Port As Int)
    If Astream.IsInitialized Then Astream.Close
    Dim i As Int = url.IndexOf("/")
    mPath = url.SubString(i)
    mHost = url.SubString2(0, i)
    sock.Initialize("sock")
    Log(mHost)
    Log(Port)
    sock.Connect(mHost, Port, 30000)
    
End Sub

Private Sub Sock_Connected (Successful As Boolean)
    If Successful Then
        Log("connected")
        boundary = ""
        Astream.Initialize(sock.InputStream, sock.OutputStream, "astream")
        Dim sTmp As String = $"GET ${mPath} HTTP/1.1
Host: ${mHost}
Connection: keep-alive

"$
        Astream.Write(sTmp.Replace(Chr(10), CRLF).GetBytes("UTF8"))
    End If
End Sub

Private Sub AStream_NewData (Buffer() As Byte)
    'Log(Buffer)
    bc.ArrayCopy(Buffer, 0, Data, index, Buffer.Length)
    index = index + Buffer.Length
    If boundary = "" Then
        Dim i1 As Int = IndexOfString("Content-Type", 0)
        If i1 > -1 Then
            Dim i2 As Int = IndexOfString(CRLF, i1 + 1)
            If i2 > -1 Then
                Dim ct As String = BytesToString(Data, i1, i2 - i1, "ASCII")
                Dim b As Int = ct.IndexOf("=")
                boundary = ct.SubString(b + 1)
            End If
        End If
    Else
        Dim b1 As Int = IndexOfString(boundary, 0)
        If b1 > -1 Then
            Dim b2 As Int = IndexOfString(boundary, b1 + 1)
            If b2 > -1 Then
                Dim startframe As Int = IndexOf(Array As Byte(0xff, 0xd8), b1)
                Dim endframe As Int = IndexOf(Array As Byte(0xff, 0xd9), b2 - 10)
                If startframe > -1 And endframe > -1 Then
                    Dim In As InputStream
                    In.InitializeFromBytesArray(Data, startframe, endframe - startframe + 2)
    #if B4J
                    Dim bmp As Image
    #else
                    Dim bmp As Bitmap
    #end if
                    bmp.Initialize2(In)
                    CallSub2(mCallback, mEventName & "_frame", bmp)
                End If
                TrimArray(b2)
                
            End If
        End If
    End If
End Sub

Private Sub TrimArray (i As Int)
    bc.ArrayCopy(Data, i, Data, 0, index - i)
    index = index - i
End Sub

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
            End If
        Next
        If b = bs.Length Then
             Return i
        End If   
    Next
    Return -1
End Sub

Private Sub AStream_Error
    Log("error")
End Sub

Private Sub Astream_Terminated
    Log("Terminated")
End Sub

Does somebody have a complete example how to realize what I want or can point to errors are have made.
Harry
 

HARRY

Active Member
Licensed User
Longtime User
Hi Erel,

No, it doesn't work either. At a certain moment the boundary value=text/htlm(???) . Then the program stops. I have been tracing FireFox, when I use it to display the image.
The answer on the GET request is:

B4X:
<html><head>
<title>Raspberry Pi - Surveillance Camera</title>
</head>
<body>
<center><h1>Raspberry Pi - Surveillance Camera</h1></center>
<center><img src="stream.mjpg" width="640" height="480"></center>
</body></html>

The B4A app gets the same answer.

For FireFox this is enough to show the stream. I don't understand.

Harry
 
Upvote 0

HARRY

Active Member
Licensed User
Longtime User
Hi Erel,
Sorry, my fault. The software I was running on the Raspberry zero did not generate JPEG frames, but MPJG. I was mislead by the documentation in which both termes were used. I loaded other software and now it works with tje MJPEG example.
 
Upvote 0
Top