使用Xuggler快速分段文件而无需解码/编码

时间:2011-11-26 21:01:32

标签: encoding playframework http-live-streaming xuggle

使用Play框架编写Java应用程序并需要一些HTTP-Live流。我打算根据需要即时分割mp4文件。我尝试了一个c-segmenter(来自Carson McDonald)并且非常快。但是,我喜欢将代码集成到我的Java应用程序中以便于控制,因此尝试了Xuggler。

然而在这个设置中,Xuggler似乎解码并重新编码了对象,因为运行它需要一些重要的时间(在MacbookPro上大约12秒内运行24秒)。有没有办法运行类似的代码,而不会做任何繁重的工作,只是为了分段切割文件?

虽然使用下面的测试代码代码非常简单:

public static void segmentMediaFile (String sourceUrl) {
    Logger.debug("Starting segmenting process...");
    IMediaReader mediaReader = ToolFactory.makeReader(sourceUrl);

    MediaSegmenterListener listener = new MediaSegmenterListener();

    IMediaReader reader = ToolFactory.makeReader(sourceUrl);

    reader.addListener(listener);
    int count = 0;

    IMediaWriter currentWriter = makeMediaWriterFromCounter(++count, reader);
    reader.addListener(currentWriter);

    while (reader.readPacket() == null)
      do {
        if (listener.newFile()) {
           reader.removeListener(currentWriter);
           currentWriter.flush();
           currentWriter.close();
           currentWriter = makeMediaWriterFromCounter(++count, reader);
           reader.addListener(currentWriter);
        }
      } while(false);
}

private static IMediaWriter makeMediaWriterFromCounter (final int counter, IMediaReader reader) {
    String destinationUrl = "./public/testdata/test-movie/";
    return ToolFactory.makeWriter(destinationUrl + counter + "_some_name.mov", reader);
}

(监听器目前只根据时间戳决定创建一个新文件)

或者这是错误的做法吗?

2 个答案:

答案 0 :(得分:0)

我根据IPacket写了代码,算法是这样的 openOutput容器设置视频和音频的流,然后从输入容器中读取数据包并写入outputContainer。 代码工作正常,没有任何例外等,但唯一的事情是我无法看到图片而不是音频工作正常。 让我知道你的身份证我会寄给你代码,也许你会弄清楚那里有什么问题。

由于

答案 1 :(得分:0)

我开发了以下代码来分割媒体文件。但是,因为我也需要编码,

我从来没有对它进行过测试(并且没有编码工作的版本),但是从外面看文件是正确的。也许它会在途中帮助某人。 (肯定不会信任输出.m3u8文件)

public static void segmentMediaFile (String sourceFile, String destinationDir, String extension) throws Exception {
    final int segmentSize = 10;
    int counter = 0;

    final IContainer input = IContainer.make();

    // open the input file
    if(!(new File(sourceFile).exists())) throw new Exception("Source file " + sourceFile + " does not exist!");
    input.open(sourceFile, IContainer.Type.READ,null);

    IContainer output = getOutputContainer(counter, input, destinationDir, extension);

    double lastNewFilePostion = 0;
    double currentFilePostion = 0;

    FileWriter fstream = new FileWriter(destinationDir + "prog_index.m3u8");
    BufferedWriter out = new BufferedWriter(fstream);
    out.write( "#EXTM3U\n#EXT-X-TARGETDURATION:10\n#EXT-X-MEDIA-SEQUENCE:0\n");
    out.close();

    for(;;)
    {
      final IPacket pkt = IPacket.make();
      if (input.readNextPacket(pkt) < 0)
            break;

      // Only needed to calculate the last segment size!
      currentFilePostion = pkt.getTimeStamp() * pkt.getTimeBase().getValue();

      if (((currentFilePostion - lastNewFilePostion) >= segmentSize) ||
              (pkt.isKeyPacket() && ((currentFilePostion - lastNewFilePostion) >= segmentSize - 0.5))){
           if(!((currentFilePostion - lastNewFilePostion) >= segmentSize)) Logger.debug("Keyframe overrulled segment at " + currentFilePostion);

           File filename = new File(output.getURL());
           int lastSegementLength = (int) (currentFilePostion - lastNewFilePostion);
           writeTrailer(output);

           fstream = new FileWriter(destinationDir + "prog_index.m3u8",true);
           out = new BufferedWriter(fstream);
           out.write("#EXTINF:" + lastSegementLength + ",\n" + filename.getName() + "\n");
           out.close();

           counter++;
           output = getOutputContainer(counter, input, destinationDir, extension);

           lastNewFilePostion = currentFilePostion;
      }

      output.writePacket(pkt, false);
    }

    // Write the m3u8 file
    File filename = new File(output.getURL());
    int lastSegementLength = (int) (currentFilePostion - lastNewFilePostion);
    String segmentList = "#EXTINF:" + lastSegementLength + ",\n" + filename.getName() + "\n";
    segmentList = segmentList + "#EXT-X-ENDLIST\n";

    fstream = new FileWriter(destinationDir + "prog_index.m3u8",true);
    out = new BufferedWriter(fstream);
    out.write(segmentList);
    out.close();

    writeTrailer(output);
}


private static IContainer getOutputContainer (final int counter, IContainer input, String destinationDir, String extension) throws Exception {
    IContainer output = IContainer.make();
    output.open(destinationDir + "segment_" + counter + "." + extension, IContainer.Type.WRITE, null);

    int numStreams = input.getNumStreams();
    for(int i = 0; i < numStreams; i++)
    {
      final IStream stream = input.getStream(i);
      final IStreamCoder coder = stream.getStreamCoder();
      coder.open();

      IStreamCoder newCoder = IStreamCoder.make(IStreamCoder.Direction.ENCODING, coder);
        if(newCoder != null ){
          output.addNewStream(i);
          output.getStream(i).setStreamCoder(newCoder);
          newCoder.open();
      } else {
          Logger.warn("Is there an invalid stream present in video file: " + input.getURL() + "! IGNORING, but this might be serious");
      }


    }

    // write the output header
    writeHeader(output);

    return output;
}

private static void writeHeader(IContainer output){
    output.writeHeader();
}

private static void writeTrailer(IContainer output){
    // write the output trailers
    output.writeTrailer();
    int streams = output.getNumStreams();
    for(int j = 0; j < streams; j++)
    {
      output.getStream(j).getStreamCoder().close();
    }
    output.close();
}