Search code examples
vlclibvlcvlcjtranscode

VLC, vlcj, RTSP, and sout


I am trying to transcode a RTSP stream into an mpeg4 stream over http for use on a webpage in a video tag. I am using vlcj and a 32-bit version of VLC installed locally. I thought I had the right sout settings, but I am getting the following error when finished.

[414c24e8] stream_out_standard stream out error: no mux specified or found by extension
[414c24e8] stream_out_standard stream out error: no mux specified or found by extension
[414d47e8] main stream output error: stream chain failed for `transcode{vcodec=mp4v, vb=1024, acodec=none}:standard{dst=std{access=http,mux=ts,dst=127.0.0.1:5555}}

The sout I am sending in the options argument to the method call is:

:sout=#transcode{vcodec=mp4v, vb=1024, acodec=none}:standard{dst=std{access=http,mux=ts,dst=127.0.0.1:5555}}

What am I doing wrong?


Update 12/30/2021

That fixed one of my problems. I still have to work out the various options to pass into the method. Thanks for the help.


Update 12/29/2021:

Here is the code I am using as a proof of concept for testing purposes and feasibility.

/*
 * This Java source file was generated by the Gradle 'init' task.
 */
package aes.video.transcoder;

import uk.co.caprica.vlcj.factory.MediaPlayerFactory;
import uk.co.caprica.vlcj.player.base.MediaPlayer;

public class App {
    private static final int EMPTY = 0;
    private static final String CAMERA_TEST_URL = "rtsp://xxx.xxx.xxx.xxx:###/media/video1";
    private static final char SOUT_SEPERATOR = ':';
    private static final char LEFT_BRACE = '{';
    private static final char RIGHT_BRACE = '}';
    private static final String SOUT="sout=#";
    
    private MediaPlayerFactory factory;
    private MediaPlayer mediaPlayer;
    private final StringBuilder sb;
    
    public App() {
        sb = new StringBuilder(256);
    }
    
    public static void main(String[] args) {
        App app = new App();
        app.transcodeTest(args);
    }
    
    public void transcodeTest(String[] args) {
        StringBuilder sbl = new StringBuilder(256);
        factory = new MediaPlayerFactory();
        mediaPlayer = factory.mediaPlayers().newEmbeddedMediaPlayer();
        
        String media = CAMERA_TEST_URL;
        String format = formatHttpStream("127.0.0.1", 5555);
        String transcode = formatTranscodeString();
        sbl.append(SOUT_SEPERATOR);
        sbl.append(SOUT);
        sbl.append(transcode);
        sbl.append(SOUT_SEPERATOR);
        sbl.append(format);
        String[] options = {sbl.toString()};
        System.out.println(options[0]);
        mediaPlayer.media().play(CAMERA_TEST_URL, options);
        
        factory.release();
    }
    
    private String formatHttpStream(String serverAddress, int serverPort) {
        sb.setLength(EMPTY);
//        sb.append(":sout=#duplicate{dst=std{access=http,mux=ts,");
        sb.append("standard{dst=std{access=http,mux=ts,");
        sb.append("dst=");
        sb.append(serverAddress);
        sb.append(':');
        sb.append(serverPort);
        sb.append(RIGHT_BRACE);
        sb.append(RIGHT_BRACE);
        return sb.toString();
    }
    
    private String formatTranscodeString() {
        sb.setLength(EMPTY);
        sb.append("transcode");
        sb.append(LEFT_BRACE);
        sb.append("vcodec=mp4v,");
        sb.append(" vb=1024,");
        sb.append(" acodec=none");
        sb.append(RIGHT_BRACE);
        return sb.toString();
    }
}

The Gradle build file is:

/*
 * This file was generated by the Gradle 'init' task.
 *
 * This generated file contains a sample Java application project to get you started.
 * For more details take a look at the 'Building Java & JVM projects' chapter in the Gradle
 * User Manual available at https://docs.gradle.org/6.8.2/userguide/building_java_projects.html
 */

plugins {
    // Apply the application plugin to add support for building a CLI application in Java.
    id 'application'
}

repositories {
    // Use JCenter for resolving dependencies.
    jcenter()
}

dependencies {
    
    // https://mvnrepository.com/artifact/uk.co.caprica/vlcj
    implementation 'uk.co.caprica:vlcj:4.7.1'
    implementation 'uk.co.caprica:vlcj:4.7.1:sources'
    implementation 'uk.co.caprica:vlcj:4.7.1:javadoc'

    
    // Use JUnit test framework.
    testImplementation 'junit:junit:4.13'

    // This dependency is used by the application.
    implementation 'com.google.guava:guava:29.0-jre'
}

application {
    // Define the main class for the application.
    mainClass = 'aes.video.transcoder.App'
}

This is only a test for proof of concept, and it will not be used in production. I think there is a problem with the sout module string I am using.


Solution

  • The streaming options need to be passed in an array, not a single string with the separator as you have used.

    This is a fragment of what you have:

    String[] options = {sbl.toString()};
    System.out.println(options[0]);
    mediaPlayer.media().play(CAMERA_TEST_URL, options);
    

    The initialisation of options is not correct here.

    Where you have SOUT_SEPARATOR you actually need to pass separate string elements in the array.

    I would also recommend looking in the vlcj test sources or the vlcj-examples project at GitHub, there are examples that format transcoding strings and pass them as media options correctly.