Используйте Xuggler для быстрого сегментирования файла без декодирования / кодирования - PullRequest
1 голос
/ 27 ноября 2011

Написание Java-приложения с использованием инфраструктуры Play и необходимости потоковой передачи HTTP-Live. Я намерен сегментировать файлы mp4 на лету, по требованию. Я попробовал c-segmenter для этого (от Carson McDonald), и это очень быстро. Тем не менее, мне нравится интегрировать код в свое Java-приложение для более простого управления, поэтому попробовал Xuggler.

Однако в этой настройке Xuggler, по-видимому, декодирует и перекодирует объект, поскольку его запуск занимает некоторое значительное время (24 секунды выполняются примерно за 12 секунд в MacbookPro). Есть ли способ запустить подобный код без какой-либо тяжелой работы, просто разрезать файл на сегменты?

Хотя это довольно просто с кодом, подобным приведенному ниже тестовому коду:

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 голосов
/ 06 января 2012

Я разработал следующий код для сегментации медиа-файлов.Однако, поскольку мне также требовалось кодирование,

Я никогда не проверял его (и у меня еще нет версии с кодировкой), но он выдает файлы, которые кажутся правильными извне.Может быть, это поможет кому-то в пути.(демонстративно не будет доверять выходному файлу .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();
}
0 голосов
/ 23 декабря 2011

Я написал код, основанный на IPacket, algo был чем-то вроде контейнера openOutput, устанавливал потоки для видео и аудио, а затем считывал пакеты из входного контейнера и записывал в outputContainer.Код работает нормально без каких-либо исключений и т. Д., Но единственное, что я не могу видеть изображения, а звук работает нормально.дайте мне знать ваш идентификатор, я вышлю вам код, может быть, вы поймете, что не так в этом.

Спасибо

...