LINUX.ORG.RU

gstreamer - как узнать длительность mpegts файла?

 


0

1

Всем доброго времени суток! Что-то я в тупике оказался.. Подскажите можно ли как-то через gstreamer узнать длительность видео-файла не проигрывая его? Т.е. есть путь к файлу, нужно узнать его длительность. Казалось бы простейшая задача, но решить ее пока никак не удается...

Буду рад любым мыслям и предложениям.



Последнее исправление: Xuch (всего исправлений: 1)

Ответ на: комментарий от Novator

Очень остроумно. Еще раз объясняю, что уже перепробовал gst_element_query_duration и с playbin2, и с uridecodebin. Выдает какую-то чепуху вместо реальной длительности. С playbin проблема, т.к. нет устройств отображения видео в целевом устройстве и попытка поставить его в состояние PLAYING приводит к ошибке gstreamer'a. К тому же мне не хотелось бы проигрывать файл для того, чтобы элементарно узнать его длительность.

Есть ли какой-нибудь другой способ. Нужно только узнать длительность файла и все.

Xuch
() автор топика

Если не ошибаюсь, то mpegts - это поточный формат. Так что если это просто дамп потока в файле, то длительность может быть вообще неизвестна без чтения всего файла. Можно только попробовать угадать приблезительную длительность по размеру файла.

Deleted
()

Буду рад любым мыслям и предложениям.

Про gstreamer ничего не скажу, но для видеопотока без индекса (а насколько я помню, в mpegts индекса нет) точно узнать его длительность без полного сканирования невозможно.

Можно узнать длительность приблизительно, если файл имеет постоянный битрейт (CBR) — поделить размер файла на битрейт. Битрейт посмотреть либо в свойствах потока (не помню, в mpegts может быть и не пишется), либо прочитать некоторое количество стартовых кадров и вычислить битрейт через их размер.

Ещё способ — если поток имеет встроенный таймкод (в mpegts может быть, может не быть), перескочить поближе к концу файла и прочитать таймкод в последней GOP — результат будет весьма точный, если таймкод правильный.

Чтобы всё это реализовать, нужен какой-то интерфейс к демультиплексору видеопотока, как с этим у gstreamer — не знаю.

cdslow ★★
()

Прочитать первый пакет, запомнить timestamp

Прочитать последний пакет, взять из него timestamp и по разнице timestamp'сов можно получить время.

Как все это делается в gstreamer хз.

AF ★★★
()
Ответ на: комментарий от Xuch

Думал «спасибо» скажешь. По первой же ссылке рабочий вариант:
1) делаешь раз
nano duration.py

#!/usr/bin/env python
# -*- coding: utf-8 -*-
from __future__ import division

import sys
import gobject
gobject.threads_init()
import pygst
pygst.require("0.10")
import gst
d = gst.parse_launch("filesrc name=source ! decodebin2 ! fakesink")
source = d.get_by_name("source")
source.set_property("location", sys.argv[1])
d.set_state(gst.STATE_PLAYING)
d.get_state()
format = gst.Format(gst.FORMAT_TIME)
duration = d.query_duration(format)[0]
d.set_state(gst.STATE_NULL)

import datetime
delta = datetime.timedelta(seconds=(duration / gst.SECOND))
print delta

2) делаешь два:
python duration.py /mnt/data/Media/Video/BeHappy.avi

и видишь на экране:

user@comp:/mnt/data/Media/Video$ python duration.py BeHappy.avi 
0:04:02.720000

Не паришься. Ты щаслиф.

Novator ★★★★★
()
Ответ на: комментарий от cdslow

Но MediaInfo моментально выдает информацию.. неужели он сканирует целый файл? Вот что выдает MediaInfo:

General ID : 1 (0x1) Format : MPEG-TS File size : 1.13 MiB Duration : 20s 899ms Overall bit rate mode : Variable Overall bit rate : 450 Kbps

Video ID : 64 (0x40) Menu ID : 1 (0x1) Format : AVC Format/Info : Advanced Video Codec Format profile : Baseline@L4.1 Format settings, CABAC : No Format settings, ReFrames : 1 frame Format settings, GOP : M=1, N=16 Codec ID : 27 Duration : 20s 899ms Bit rate : 428 Kbps Width : 1 600 pixels Height : 1 200 pixels Display aspect ratio : 4:3 Color space : YUV Chroma subsampling : 4:2:0 Bit depth : 8 bits Scan type : Progressive Stream size : 1.07 MiB (95%) Color primaries : BT.709 Transfer characteristics : BT.709 Matrix coefficients : BT.709

Xuch
() автор топика
Ответ на: комментарий от Novator

Novator, спасибо, только смущают две вещи: 1) Это питон, у меня прога на си 2) Результат get_state получается никак не анализируется... 3) Пайп вгоняется в состояние PLAYING... что в итоге происходит? Как-то получается чтобы узнать элементарную длительность потока мы воспроизводим поток.. Не из пушки по воробьям?

Xuch
() автор топика
Ответ на: комментарий от Xuch

неужели он сканирует целый файл?

Так на современном компьютере чтобы прочитать 1 МБ много времени не требуется. А для того, чтобы посчитать кадры, их распаковывать не нужно, достаточно пробежаться по заголовкам.

Можешь проверить через strace, читает MediaInfo весь файл, или нет :)

cdslow ★★
()
Ответ на: комментарий от Novator

Что-то не работает у меня это... Ниже код.

typedef struct _MinfoData
{
  GstElement *Pipeline, *Source, *Bin, *Sink;
  gint nvid;
  gint naud;
  gint ntext;

  size_t cam_num;
} MinfoData;


int Minfo::RequestMetadata2(string path)
{
  const char *class_name = "Minfo::RequestMetadata2";
  MinfoData *data;
  GstBus *Bus;
  GstStateChangeReturn Ret;

  gst_init(NULL, NULL);

  sprintf(str, "DEBUG: Cam num %d Full path is: '%s'\n", (int) data->cam_num, path.c_str());
  AppendLog(str, class_name, DEBUG);

  data->Pipeline = gst_pipeline_new("Pipeline");
  data->Source = gst_element_factory_make("filesrc", "Source");
  g_object_set(data->Source, "location", path.c_str(), NULL);
  data->Bin = gst_element_factory_make("decodebin2", "Bin");
  data->Sink = gst_element_factory_make("fakesink", "Sink");

  gst_bin_add_many(GST_BIN(data->Pipeline), data->Source, data->Bin, NULL);

  gst_element_link(data->Source, data->Bin);
  gst_element_link(data->Bin, data->Sink);

  gst_element_set_state(data->Pipeline, GST_STATE_PLAYING);

  while(1)
    {
      gint64 s = 0;
      GstFormat fmt = GST_FORMAT_TIME;

      Ret = gst_element_get_state(data->Pipeline, NULL, NULL, ((GstClockTime)1e9));

      gst_element_query_duration(data->Pipeline, &fmt, &s);
      sprintf(str, "DEBUG: Duration is: %" GST_TIME_FORMAT "\n", GST_TIME_ARGS(s));
      AppendLog(str, class_name, DEBUG);
      sprintf(str, "DEBUG: Dur: %lld\n", s/GST_SECOND);
      AppendLog(str, class_name, DEBUG);
    }

  return 0;
}

Для любых файлов все время выдает нули... Что я делаю не так?

Xuch
() автор топика
Ответ на: комментарий от Xuch

Пайп вгоняется в состояние PLAYING... что в итоге происходит?

Поток запускается, гонится в фейковый слив, но тут же останавливается.

Для любых файлов все время выдает нули... Что я делаю не так?

У меня на питоне робит, я проверял. А ты на питоне пробовал? Если на питоне робит, а в си нет, то значит где-то ошибка в си - ищи, я в сях не спец.

Novator ★★★★★
()
Ответ на: комментарий от Novator

Не могу я туда питон поставить.. это одноплатный компьютер, там просто нет ресурсов для установки питона.

Xuch
() автор топика
Ответ на: комментарий от Xuch

Оппа.. А там вобще гстример работает? Может встал криво? Например через утилиту gst-launch поток запускается?

Novator ★★★★★
()
Ответ на: комментарий от Novator

Да работает там gstreamer прекрасно, я им эти файлы и пишу. Просто на определенном этапе мне нужно определить длительность записанных файлов.

Xuch
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.