【问题标题】:wowza java api inject captioningwowza java api注入字幕
【发布时间】:2016-11-02 16:58:12
【问题描述】:

我们有一堆 .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 调用,但该部分被描述为“旧版”。我可以扩展它,但由于它是“遗留的”,我担心模块所依赖的任何 API 都可能不适用于更高版本的 WMS。

在 PublishingProviderMediaReader 调用之后,是否有一种低级方式(“传统”方式除外)告诉系统立即加载 ttml 文件(或只是手动注入文本)?

下面是上面链接粘贴的代码

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;
    }

}

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

【问题讨论】:

    标签: java wowza


    【解决方案1】:

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

    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 对象来读取您的文件并使用上述方法注入数据。

    【讨论】:

    • 谢谢。 setCaption 函数从字面上插入并为 rtmp 工作
    • injectMetaData 的目的是什么?更具体地说,如何注入具有特定开始/结束时间的字幕?
    猜你喜欢
    • 2014-07-15
    • 2018-06-19
    • 2012-01-19
    • 2015-01-01
    • 2011-07-01
    • 2021-01-08
    • 2018-04-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多