wowza java api 插入字幕

wowza java api inject captioning

我们有一堆 .mp4 文件及其关联的 .ttml 开放式字幕文件。我们正在使用 Wowza 根据动态计划动态加载和流式传输这些文件,而不会中断流。

我能够按照此处的教程 (https://www.wowza.com/docs/how-to-use-ipublishingprovider-api-to-publish-server-side-live-streams) 在指定时间流式传输单个 mp4 文件。

但是,我找不到 Java API 命令来注入关联的字幕文件。我找到了这个页面( https://www.wowza.com/docs/how-to-configure-closed-captioning-for-live-streaming ),它没有谈论 Java API 而是一个配置设置。页面末尾是一个显示一些 API 调用的示例包,但该部分被描述为 "legacy"。我可以扩展它,但由于它是 "legacy",我担心模块所依赖的任何 API 可能无法在更高版本的 WMS 中使用。

是否有低级方法(除了 "legacy" 方法)告诉系统在 PublishingProviderMediaReader 调用后立即加载 ttml 文件(或只是手动注入文本)?

下面是从上面link粘贴的代码

package com.wowza.wms.plugin.test.integration;

import com.wowza.wms.stream.publish.*;
import com.wowza.wms.vhost.*;
import com.wowza.wms.logging.*;

public class ServerPublisherWorker extends Thread
{
    private long sleepTime = 75;
    private boolean running = true;
    private Object lock = new Object();

    private String applicationName = "live";
    private String vodStreamName = "mp4:sample.mp4";
    private String liveStreamName = "myStream";
    private String publishStreamName = "publishstream";
    private int cycleTime = 10000;

    public synchronized void quit()
    {
        synchronized(lock)
        {
            running = false;
        }
    }

    public void run()
    {
        WMSLoggerFactory.getLogger(ServerPublisherWorker.class).info("ServerPublisherWorker.run: START");

        long startTime = System.currentTimeMillis();
        long playStartTime = startTime;

        try
        {
            IVHost vhost = VHostSingleton.getInstance(VHost.VHOST_DEFAULT);
            Publisher publisher = Publisher.createInstance(vhost, applicationName);

            publisher.publish(publishStreamName);

            long nextSwitch = playStartTime + cycleTime;
            long nextType = 0;
            IPublishingProvider provider = new PublishingProviderMediaReader(publisher, playStartTime, vodStreamName);
            //provider.seek(20000);
            provider.setRealTimeStartTime(startTime);

            WMSLoggerFactory.getLogger(ServerPublisherWorker.class).info("ServerPublisherWorker.run: Start with vod stream: "+vodStreamName);

            while(true)
            {
                boolean moreInFile = provider!=null?provider.play(publisher):false;

                long currentTime = System.currentTimeMillis();
                if (!moreInFile || currentTime > nextSwitch)
                {
                    if (provider != null)
                        provider.close();
                    provider = null;

                    if ((nextType % 2) == 0)
                    {
                        provider = new PublishingProviderLive(publisher, publisher.getMaxTimecode(), liveStreamName);
                        //((PublishingProviderLive)provider).setStartOnPreviousKeyFrame(false);
                        provider.setRealTimeStartTime(currentTime);

                        WMSLoggerFactory.getLogger(ServerPublisherWorker.class).info("ServerPublisherWorker.run: Switch to live stream: "+liveStreamName);
                    }
                    else
                    {
                        provider = new PublishingProviderMediaReader(publisher, publisher.getMaxTimecode(), vodStreamName);
                        //provider.seek(20000);
                        provider.setRealTimeStartTime(currentTime);

                        WMSLoggerFactory.getLogger(ServerPublisherWorker.class).info("ServerPublisherWorker.run: Switch to vod stream: "+vodStreamName);
                    }

                    nextSwitch = currentTime + cycleTime;
                    nextType++;

                    if (nextType == 100)
                        break;
                }
                else
                    sleep(sleepTime);

                synchronized(lock)
                {
                    if (!running)
                        break;
                }
            }

            provider.close();

            publisher.publish(null);

            synchronized(lock)
            {
                running = false;
            }
        }
        catch (Exception e)
        {
            WMSLoggerFactory.getLogger(ServerPublisherWorker.class).error("ServerPublisherWorker.run: "+e.toString());
            e.printStackTrace();
        }

        WMSLoggerFactory.getLogger(ServerPublisherWorker.class).info("ServerPublisherWorker.run: STOP");
    }
}

以及调用上述代码的基础监听器:

package com.wowza.wms.plugin.test.integration;

import com.wowza.wms.server.*;

public class ServerPublisherServerListener implements IServerNotify
{
    ServerPublisherWorker worker = null;

    public void onServerCreate(IServer server)
    {
    }

    public void onServerInit(IServer server)
    {
        worker = new ServerPublisherWorker();
        worker.start();
    }

    public void onServerShutdownComplete(IServer server)
    {
    }

    public void onServerShutdownStart(IServer server)
    {
        if (worker != null)
            worker.quit();
        worker = null;
    }

}

非常感谢任何帮助或意见。提前谢谢你。

您可以使用以下方法从流中插入提示点或元数据:

package com.wowza.example.module;

import com.wowza.wms.amf.*;
import com.wowza.wms.client.*;
import com.wowza.wms.module.*;
import com.wowza.wms.request.*;
import com.wowza.wms.stream.*;

public class ModuleInjectData extends ModuleBase {

    public void setCaption (IClient client, RequestFunction function, AMFDataList params)
    {
        String streamname = params.getString(PARAM1);
        String text =  params.getString(PARAM2);
        String language = params.getString(PARAM3);
        String trackid = params.getString(PARAM4);

        IMediaStream stream = client.getAppInstance().getStreams().getStream(streamname);

        //essential code
        AMFDataMixedArray data = new AMFDataMixedArray();
        data.put("text", new AMFDataItem(text));
        data.put("language", new AMFDataItem(language));
        data.put("trackid", new AMFDataItem(trackid));
        stream.sendDirect("onTextData", data);
        ((MediaStream)stream).processSendDirectMessages();
        getLogger().info("Caption: " + text);
    }

    public void injectMetaData(IClient client, RequestFunction function, AMFDataList params)
    {
        String streamName = params.getString(PARAM1);
        String data =  params.getString(PARAM2);
        IMediaStream stream = client.getAppInstance().getStreams().getStream(streamName);
        if (stream != null)
        {
            AMFDataList amfList = new AMFDataList();

            amfList.add(new AMFDataItem("@setDataFrame"));
            amfList.add(new AMFDataItem("onMetaData"));

            AMFDataMixedArray metaData = new AMFDataMixedArray();

            metaData.put("param1", data);
            metaData.put("param2", new AMFDataItem("data2"));

            amfList.add(metaData);

            synchronized(stream)
            {
                byte[] dataData = amfList.serialize();
                int size = dataData.length;
                long timecode = Math.max(stream.getAudioTC(), stream.getVideoTC());
                stream.setDataTC(timecode);
                stream.setDataSize(size);
                stream.startDataPacket();
                stream.addDataData(dataData, 0, size);
            }
        }
    }
}

您将需要创建一个 BufferedReader 对象来读取您的文件并使用上述方法注入数据。