LINUX.ORG.RU

Созданный pipeline с помощью gst_parse_launch всегда 0

 , , ,


0

1

Я создаю pipeline с помощью функции gstreamer gst_parse_launch, но всегда получаю 0, даже тестовые несложные конструкции не проходят. Мне необходимо передавать видеопоток с веб-камеры между двумя android устройствами. Устройства подключаются к ubuntu-серверу (через gRPC). Приложение написано на Unity. Gstreamer подключаю из libgstreamer_android.so, который сгенерировала с помощью CMake.

private string BuildGStreamerPipeline(string address, string port)
{
    string pipelineStr = "videotestsrc ! videoconvert ! autovideosink";

    return pipelineStr;

}
private void StartGStreamerPipeline(string serverAddress)
{
    if (!GStreamerPlugin.isInitialized)
    {
        Debug.LogError("GStreamer is not Init!");
        return;
    }

    InitializeVideoTexture();

    var ipAddress = serverAddress.Split(':')[0];
    string pipelineStr = BuildGStreamerPipeline(ipAddress, GST_PORT.ToString());
    Debug.Log($"Using pipeline: {pipelineStr}");

    IntPtr pipeline = GStreamerPlugin.CreatePipeline(pipelineStr);
    Debug.Log("Pipeline: " + pipeline);
    if (pipeline == IntPtr.Zero)
    {
        Debug.Log("Failed pipeline");
        return;
    }

    bool stateResult = GStreamerPlugin.SetPipelineState(pipeline, GstState.GST_STATE_PLAYING);
    if (!stateResult)
    {
        Debug.LogError("Pipeline state change failed");
        return;
    }

    StartCoroutine(UpdatePreviewRoutine(pipeline));
}

Генерирую .so файл следующим образом:

cmake_minimum_required(VERSION 3.10...3.31)

set(CMAKE_SYSTEM_NAME Android)
set(ANDROID_PLATFORM android-29)
set(ANDROID_ABI arm64-v8a)
set(CMAKE_ANDROID_ARCH_ABI arm64-v8a)

project(gstreamer_android)

# GStreamer paths
set(GSTREAMER_ROOT_DIR "D:/gstreamer-1.0-android-universal-1.14.5")
set(GSTREAMER_ROOT_ANDROID ${GSTREAMER_ROOT_DIR})
set(GSTREAMER_ARCH "arm64")
set(GSTREAMER_LIB_DIR "${GSTREAMER_ROOT_ANDROID}/${GSTREAMER_ARCH}/lib")
set(GSTREAMER_PLUGINS_DIR "${GSTREAMER_ROOT_ANDROID}/${GSTREAMER_ARCH}/lib/gstreamer-1.0")

# Add core plugins needed for video streaming
set(GST_PLUGIN_CORE "${GSTREAMER_PLUGINS_DIR}/libgstcoreelements.a")
set(GST_PLUGIN_VIDEOCONVERT "${GSTREAMER_PLUGINS_DIR}/libgstvideoconvert.a")
set(GST_PLUGIN_VIDEOTESTSRC "${GSTREAMER_PLUGINS_DIR}/libgstvideotestsrc.a")
set(GST_PLUGIN_X264 "${GSTREAMER_PLUGINS_DIR}/libgstx264.a")
set(GST_PLUGIN_RTP "${GSTREAMER_PLUGINS_DIR}/libgstrtp.a")
set(GST_PLUGIN_UDP "${GSTREAMER_PLUGINS_DIR}/libgstudp.a")
set(GST_PLUGIN_APP "${GSTREAMER_PLUGINS_DIR}/libgstapp.a")

# Find Android log library
find_library(log-lib log)

# Include directories
include_directories(
    ${GSTREAMER_ROOT_ANDROID}/${GSTREAMER_ARCH}/include/gstreamer-1.0
    ${GSTREAMER_ROOT_ANDROID}/${GSTREAMER_ARCH}/include/glib-2.0
    ${GSTREAMER_ROOT_ANDROID}/${GSTREAMER_ARCH}/lib/glib-2.0/include
)

# Create the shared library
add_library(gstreamer_android SHARED
    src/gstreamer_android.cpp
)

target_link_libraries(gstreamer_android
    # Core GStreamer - order is important!
    ${GSTREAMER_LIB_DIR}/libgstreamer-1.0.a
    ${GSTREAMER_LIB_DIR}/libgstbase-1.0.a
    ${GSTREAMER_LIB_DIR}/libgstpbutils-1.0.a
    ${GSTREAMER_LIB_DIR}/libgstvideo-1.0.a
    ${GSTREAMER_LIB_DIR}/libgstapp-1.0.a

    # Core GLib - these must come before other glib-dependent libraries
    ${GSTREAMER_LIB_DIR}/libglib-2.0.a
    ${GSTREAMER_LIB_DIR}/libgobject-2.0.a
    ${GSTREAMER_LIB_DIR}/libgmodule-2.0.a
    ${GSTREAMER_LIB_DIR}/libgthread-2.0.a
    ${GSTREAMER_LIB_DIR}/libgio-2.0.a

    # Plugin elements - after core libraries
    ${GSTREAMER_PLUGINS_DIR}/libgstcoreelements.a
    ${GSTREAMER_PLUGINS_DIR}/libgstapp.a
    ${GSTREAMER_PLUGINS_DIR}/libgstvideotestsrc.a
    ${GSTREAMER_PLUGINS_DIR}/libgstvideoconvert.a
    ${GSTREAMER_PLUGINS_DIR}/libgstx264.a
    ${GSTREAMER_PLUGINS_DIR}/libgstrtp.a
    ${GSTREAMER_PLUGINS_DIR}/libgstudp.a

    # Additional GStreamer libs
    ${GSTREAMER_LIB_DIR}/libgstnet-1.0.a
    ${GSTREAMER_LIB_DIR}/libgstcontroller-1.0.a
    ${GSTREAMER_LIB_DIR}/libgsttag-1.0.a
    ${GSTREAMER_LIB_DIR}/libgstrtp-1.0.a
    ${GSTREAMER_LIB_DIR}/libgstsdp-1.0.a
    ${GSTREAMER_LIB_DIR}/libgstrtsp-1.0.a
    
    # Support libraries
    ${GSTREAMER_LIB_DIR}/libffi.a
    ${GSTREAMER_LIB_DIR}/libiconv.a
    ${GSTREAMER_LIB_DIR}/libintl.a
    ${GSTREAMER_LIB_DIR}/libz.a

    # System libraries
    ${log-lib}
    -landroid
    -ldl
    -lm
    -latomic

    # Link some libraries twice to resolve circular dependencies
    ${GSTREAMER_LIB_DIR}/libglib-2.0.a
    ${GSTREAMER_LIB_DIR}/libgobject-2.0.a
    ${GSTREAMER_LIB_DIR}/libgstreamer-1.0.a
)
# Add definitions
target_compile_definitions(gstreamer_android PRIVATE
    ANDROID_NDK
    GST_DISABLE_DEPRECATED
    GST_USE_UNSTABLE_API
    _GNU_SOURCE
    HAVE_CONFIG_H
    GST_PLUGIN_BUILD_STATIC
    GLIB_STATIC_COMPILATION
    G_DISABLE_DEPRECATED
)
#include <jni.h>
#include <android/log.h>
#include <gst/gst.h>
#include <gst/app/gstappsink.h>
#include <string>

#define TAG "GStreamer"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__)

static GstElement* pipeline = nullptr;

extern "C" {

    JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) {
        LOGD("JNI_OnLoad called");

        JNIEnv* env;
        if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
            LOGE("Failed to get JNI environment");
            return -1;
        }

        gst_init(nullptr, nullptr);
        LOGD("GStreamer initialized successfully");

        return JNI_VERSION_1_6;
    }

    JNIEXPORT void JNICALL JNI_OnUnload(JavaVM* vm, void* reserved) {
        LOGD("JNI_OnUnload called");
        if (pipeline) {
            gst_element_set_state(pipeline, GST_STATE_NULL);
            gst_object_unref(pipeline);
        }
        gst_deinit();
    }

    JNIEXPORT jboolean JNICALL
        Java_com_yourpackage_GStreamerPlugin_gst_1is_1initialized(JNIEnv* env, jclass type) {
        return static_cast<jboolean>(gst_is_initialized());
    }

    JNIEXPORT void JNICALL
        Java_com_yourpackage_GStreamerPlugin_gst_1init(JNIEnv* env, jclass type) {
        if (!gst_is_initialized()) {
            gst_init(nullptr, nullptr);
        }
    }

    JNIEXPORT jobject JNICALL
        Java_com_yourpackage_GStreamerPlugin_gst_1parse_1launch(JNIEnv* env, jobject thiz, jstring pipelineStr) {
        const char* pipeline_desc = env->GetStringUTFChars(pipelineStr, nullptr);
        GError* error = nullptr;

        pipeline = gst_parse_launch(pipeline_desc, &error);

        if (error != nullptr) {
            LOGE("Failed to create pipeline: %s", error->message);
            g_error_free(error);
            env->ReleaseStringUTFChars(pipelineStr, pipeline_desc);
            return nullptr;
        }

        env->ReleaseStringUTFChars(pipelineStr, pipeline_desc);
        return env->NewDirectByteBuffer(pipeline, 0);
    }

    JNIEXPORT jboolean JNICALL
        Java_com_yourpackage_GStreamerPlugin_gst_1element_1set_1state(JNIEnv* env, jobject thiz, jobject pipelineRef, jint state) {
        GstElement* pipeline = static_cast<GstElement*>(env->GetDirectBufferAddress(pipelineRef));
        GstStateChangeReturn ret = gst_element_set_state(pipeline, static_cast<GstState>(state));
        return ret != GST_STATE_CHANGE_FAILURE;
    }

    JNIEXPORT jboolean JNICALL
        Java_com_yourcompany_GStreamerNative_gst_1app_1sink_1pull_1sample(JNIEnv* env, jobject thiz, jlong sink_ptr, jbyteArray buffer)
    {
        GstAppSink* appsink = GST_APP_SINK(reinterpret_cast<GstElement*>(sink_ptr));

        GstSample* sample = gst_app_sink_pull_sample(appsink);
        if (sample) {
            GstBuffer* buf = gst_sample_get_buffer(sample);
            GstMapInfo map;

            if (gst_buffer_map(buf, &map, GST_MAP_READ)) {
                env->SetByteArrayRegion(buffer, 0, map.size, reinterpret_cast<jbyte*>(map.data));
                gst_buffer_unmap(buf, &map);
                gst_sample_unref(sample);
                return JNI_TRUE;
            }

            gst_sample_unref(sample);
        }
        return JNI_FALSE;
    }

}

Перемещено Dimez из general


Немного не по теме, но так CMake’ом пользовались 10 лет назад, когда никто не умел. Почитай, как правильно cmake использовать. Искать в стороно imported targets, toolchain file.

UVV ★★★★★
()