Форум программистов, компьютерный форум CyberForum.ru
Наши страницы

С++ для начинающих

Войти
Регистрация
Восстановить пароль
 
Рейтинг: Рейтинг темы: голосов - 12, средняя оценка - 4.83
cyberguz
6 / 6 / 0
Регистрация: 01.12.2010
Сообщений: 105
#1

gstreamer динамическая смена "location" для filesink - C++

05.12.2011, 15:04. Просмотров 1668. Ответов 0
Метки нет (Все метки)

Задача была такая - писать видео с камеры, и по мере достижения условий максимальный размер файла или максимальное время записи, а также по команде извне, переходить к записи в новый файл. При этом необходимо чтобы не терялись данные, т.е. (насколько я понимаю) не останавливать поток.

Это, значицца - класс для игр с gstreamer.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class GstRecorder : public BaseWorker <string, string>
{
private:
    GMainLoop* loop;
    gpointer pipeline;
    gpointer src_bin;
    gpointer sink_bin[2];
    gpointer filesink[2];
    gpointer queue_out[2];
    gpointer tee;
    bool running;
    string _path;
    string _currFilename;
    string _currFileEx;
public:
    GstRecorder () : pipeline(0), filesink({0}), sink_bin({0}), src_bin(0), tee(0), queue_out({0}) {}
    virtual void process (string devName, string path);
    void stop (void);
    void rotate (void);
};
Это - функция, выполняющаяся в отдельном потоке.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
void GstRecorder::process (string devName, string path)
{
    GstBus* bus;
    GstElement  *src,
                *queue_input,
                *queue_before_tee,
                *rate,
                *enc,
                *mux,
                *frames,
                *deinterlace;
 
    TRACE << "GstRecorder::process " << devName << " " << path;
 
//  int argc = 0;
//  const char* argv[] = {""};
//  gst_init(&argc, &argv);
 
    TRACE << "init";
    gst_init(0, 0);
 
    TRACE << "new loop";
    loop = g_main_loop_new(NULL, FALSE);
 
    TRACE << "create element";
    pipeline    = gst_pipeline_new ("video-recorder");
    src_bin     = gst_bin_new ("src_bin");
    sink_bin[0] = gst_bin_new ("sink0_bin");
    sink_bin[1] = gst_bin_new ("sink1_bin");
    src         = gst_element_factory_make ("dshowvideosrc",     "src");
    queue_input     = gst_element_factory_make ("queue",            "queue0");
    queue_before_tee        = gst_element_factory_make ("queue",            "queue1");
    queue_out[0]        = gst_element_factory_make ("queue",            "queue2");
    queue_out[1]        = gst_element_factory_make ("queue",            "queue3");
    tee         = gst_element_factory_make ("tee",              "tee");
    deinterlace = gst_element_factory_make ("deinterlace",  "deinterlace");
    rate        = gst_element_factory_make ("videorate",        "rate");
    frames      = gst_element_factory_make ("capsfilter",       "frames");
    enc         = gst_element_factory_make ("xvidenc",          "enc");
    mux         = gst_element_factory_make ("matroskamux",          "mux");
    filesink[0]         = gst_element_factory_make ("filesink",             "sink");
    filesink[1]         = gst_element_factory_make ("filesink",             "sink1");
 
 
    if
    (
        !pipeline || !src || !tee || !queue_input || !queue_before_tee || !queue_out[0]
        || !queue_out[1] || !rate || !enc || !mux || !filesink[0] || !filesink[1] || !frames || !deinterlace
        || !src_bin || !sink_bin[0] || !sink_bin[1]
    )
    {
        LOG_ERROR << "One element could not be created. Exiting.";
    }
    else
    {
        _currFilename = "1";
        _currFileEx = ".mkv";
        _path = path;
 
        TRACE << "setting params";
        g_object_set(G_OBJECT (src), "device-name", devName.c_str(), NULL);
        g_object_set(G_OBJECT (enc), "greyscale", 1, NULL);
//      g_object_set(G_OBJECT (enc), "bitrate", 10000, NULL);
        g_object_set(G_OBJECT (filesink[0]), "location", (_path + _currFilename + _currFileEx).c_str(), NULL);
//      g_object_set(G_OBJECT (sink), "location", (_path + "0" + _currFileEx).c_str(), NULL);
        GstCaps *caps = gst_caps_from_string("video/x-raw-yuv,framerate=12/1");
        g_object_set(G_OBJECT (frames), "caps", caps, NULL);
 
        TRACE << "add watch";
        bus = gst_pipeline_get_bus(GST_PIPELINE (pipeline));
        gst_bus_add_watch(bus, bus_call, loop);
        gst_object_unref(bus);
 
        TRACE << "add elements";
        gst_bin_add_many(GST_BIN(src_bin), src, queue_input, queue_before_tee, (GstElement*)tee, rate, frames, enc, mux, deinterlace, NULL);
        gst_bin_add_many(GST_BIN(sink_bin[0]), (GstElement*)queue_out[0], (GstElement*)filesink[0], NULL);
        gst_bin_add_many(GST_BIN(sink_bin[1]), (GstElement*)queue_out[1], (GstElement*)filesink[1], NULL);
        gst_bin_add(GST_BIN(pipeline), (GstElement*)src_bin);
        gst_bin_add(GST_BIN(pipeline), (GstElement*)sink_bin[0]);
        gst_bin_add(GST_BIN(pipeline), (GstElement*)sink_bin[1]);
 
        TRACE << "linking";
        gst_element_link_many(src, queue_input, deinterlace, rate, frames, enc, mux, queue_before_tee, (GstElement*)tee, NULL);
        gst_element_link_many((GstElement*)queue_out[0], (GstElement*)filesink[0], NULL);
        gst_element_link_many((GstElement*)queue_out[1], (GstElement*)filesink[1], NULL);
        gst_element_link((GstElement*)tee, (GstElement*)queue_out[0]);
        gst_element_link((GstElement*)tee, (GstElement*)queue_out[1]);
 
        TRACE << "set state PLAYING";
//      gst_element_set_state((GstElement*)pipeline, GST_STATE_PLAYING);
        gst_element_set_state((GstElement*)sink_bin[0], GST_STATE_PLAYING);
        gst_element_set_state((GstElement*)src_bin, GST_STATE_PLAYING);
 
        TRACE << "running";
        running = true;
        g_main_loop_run(loop);
        running = false;
 
        TRACE << "set state NULL";
        gst_element_set_state((GstElement*)pipeline, GST_STATE_NULL);
 
        gst_object_unref(GST_OBJECT(pipeline));
    }
 
    TRACE << "GstRecorder::process return";
}
Это - обработчик команды "сменить файл для сохранения видеопотока":
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
void GstRecorder::rotate (void)
{
    //искать элемент по имени надо в бине:      gst_bin_get_by_name()
 
    //TODO: синхронизация
    TRACE << "GstRecorder::rotate";
    if (running)
    {
        /* следующее имя для файла */
        int n = strtol(_currFilename.c_str(), 0, 0);
        TRACE << "n = " << n;
        n++;
        stringstream ss;
        ss << n;
        ss >> _currFilename;
        TRACE << "_currFilename = " << _currFilename;
 
        /* меняем местами указатели на синки и бины */
        GstStateChangeReturn ret;
        gboolean ok;
        gpointer tmp = filesink[0];
        filesink[0] = filesink[1];
        filesink[1] = tmp;
        tmp = sink_bin[0];
        sink_bin[0] = sink_bin[1];
        sink_bin[1] = tmp;
 
        /* устанавливаем новое имя файла для не запущенного синка [0] */
        g_object_set(G_OBJECT(filesink[0]), "location", (_path + _currFilename + _currFileEx).c_str(), NULL);
 
        /* добавляем бин */
//      ok = gst_bin_add(GST_BIN(pipeline), (GstElement*)sink_bin[0]);
//      TRACE << "ok = " << ok;
 
        /* соединяем */
//      ok = gst_element_link((GstElement*)tee, (GstElement*)queue_out[0]);
//      TRACE << "ok = " << ok;
 
        /* запускаем бин */
        ret = gst_element_set_state((GstElement*)sink_bin[0], GST_STATE_PLAYING);
        TRACE << "ret = " << ret;
 
        /* отправляем запущенному бину [1] конец потока */
        GstEvent* event = gst_event_new_eos();
        ok = gst_element_send_event((GstElement*)sink_bin[1], event);
        TRACE << "ok = " << ok;
 
        /* останавливаем запущенный ранее бин [1] и освобождаем его ресурсы */
        ret = gst_element_set_state((GstElement*)sink_bin[1], GST_STATE_NULL);
        TRACE << "ret = " << ret;
 
        /* рассоединяем */
//      gst_element_unlink((GstElement*)tee, (GstElement*)queue_out[1]);
 
        /* удаляем бин */
//      ok = gst_bin_remove(GST_BIN(pipeline), (GstElement*)sink_bin[1]);
//      TRACE << "ok = " << ok;
    }
    TRACE << "GstRecorder::rotate return";
}
Идея была простая - вывожу через tee в два файла, один включен, другой выключен. Потом меняю, при этом сначала один включаю, потом другой выключаю - по идее куски видео должны перекрываться и ничего не потеряется.
Если не подсоединять второй бин вообще, то при соединении
Код
ok = gst_element_link((GstElement*)tee, (GstElement*)queue_out[0]);
возвращается false - т.е. не соединяется, естественно потом, после остановки работающего бина идёт ошибка, т.к. нет sink.
Если сразу всё соединить, но не запускать второй бин - вообще запись не запускается.


Подскажите, пожалуйста, кто что-нибудь знает?
Подозреваю, что ситуация типичная, но в доках ничего не нашёл, а google находит только неудовлетворённые вопросы на форумах.

Заранее спасибо.

Добавлено через 20 минут
Так, видимо в итоге вопрос сводится к более общему вопросу: позволяет ли gstreamer динамически перестраивать pipeline без его остановки?

Добавлено через 1 час 53 минуты
Урраааа Заработало!

Фишка была в том, что при добавлении элементов - добавляем, запускаем, соединяем; а при удалении - отсоединяем, останавливаем, удаляем.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
void GstRecorder::rotate (void)
{
    //TODO: синхронизация
    TRACE << "GstRecorder::rotate";
    if (running)
    {
        /* следующее имя для файла */
        int n = strtol(_currFilename.c_str(), 0, 0);
        TRACE << "n = " << n;
        n++;
        stringstream ss;
        ss << n;
        ss >> _currFilename;
        TRACE << "_currFilename = " << _currFilename;
 
        /* меняем местами указатели на синки и бины */
        GstStateChangeReturn ret;
        gboolean ok;
        gpointer tmp = filesink[0];
        filesink[0] = filesink[1];
        filesink[1] = tmp;
        tmp = sink_bin[0];
        sink_bin[0] = sink_bin[1];
        sink_bin[1] = tmp;
        tmp = queue_out[0];
        queue_out[0] = queue_out[1];
        queue_out[1] = tmp;
 
        /* устанавливаем новое имя файла для не запущенного синка [0] */
        g_object_set(G_OBJECT(filesink[0]), "location", (_path + _currFilename + _currFileEx).c_str(), NULL);
 
        /* добавляем бин */
        ok = gst_bin_add(GST_BIN(pipeline), (GstElement*)sink_bin[0]);
        TRACE << "ok = " << ok;
 
        /* запускаем бин */
        ok = gst_element_sync_state_with_parent((GstElement*)sink_bin[0]);
        TRACE << "ok = " << ok;
 
        /* соединяем */
        ok = gst_element_link((GstElement*)tee, (GstElement*)queue_out[0]);
        TRACE << "ok = " << ok;
 
        /* отправляем запущенному бину [1] конец потока */
        GstEvent* event = gst_event_new_eos();
        ok = gst_element_send_event((GstElement*)queue_out[1], event);
        TRACE << "ok = " << ok;
 
        /* рассоединяем */
        gst_element_unlink((GstElement*)tee, (GstElement*)queue_out[1]);
 
        /* останавливаем запущенный ранее бин [1] и освобождаем его ресурсы */
        ret = gst_element_set_state((GstElement*)sink_bin[1], GST_STATE_NULL);
        TRACE << "ret = " << ret;
 
        /* удаляем бин */
        ok = gst_bin_remove(GST_BIN(pipeline), (GstElement*)sink_bin[1]);
        TRACE << "ok = " << ok;
    }
    TRACE << "GstRecorder::rotate return";
}
Ещй важный момент - для каждого файла - отдельный контейнер, проще всего (на мой взгляд) поставить отдельные matroskamux для каждого sink после tee.
C++
1
2
3
4
5
        TRACE << "linking";
        gst_element_link_many(src, queue_input, deinterlace, rate, frames, enc, queue_before_tee, (GstElement*)tee, NULL);
        gst_element_link_many((GstElement*)queue_out[0], mux[0], (GstElement*)filesink[0], NULL);
        gst_element_link_many((GstElement*)queue_out[1], mux[1], (GstElement*)filesink[1], NULL);
        gst_element_link((GstElement*)tee, (GstElement*)queue_out[0]);
Добавлено через 16 минут
Рано обрадовался ( - работает только один раз, при следующем вызове
C++
1
2
3
    /* добавляем бин */
        ok = gst_bin_add(GST_BIN(pipeline), (GstElement*)sink_bin[0]);
        TRACE << "ok = " << ok;
возвращает 0, ну и конечно следующий файл не открывается, а после
C++
1
2
3
4
/* отправляем запущенному бину [1] конец потока */
        GstEvent* event = gst_event_new_eos();
        ok = gst_element_send_event((GstElement*)queue_out[1], event);
        TRACE << "ok = " << ok;
весь pipeline получает сигнал EOS, видимо из-за того, что отключается последний sink.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
05.12.2011, 15:04
Здравствуйте! Я подобрал для вас темы с ответами на вопрос gstreamer динамическая смена "location" для filesink (C++):

Создание структуры "префиксное дерево". Ошибка "Access violation writing location". - C++
Есть структура данных - бор или префиксное дерево. class trie { char value; // символ узла trie** pointers; // ссылки на...

Ошибки: "invalid use of non-static data member", "error: from this location" - C++
Здравствуйте. Помогите пожалуйста понять в чём я не прав. Почему компилятор не даёт объявить указатель на структуру и почему я не могу...

В зависимости от времени года "весна", "лето", "осень", "зима" определить погоду "тепло", "жарко", "холодно", "очень холодно" - C++
В зависимости от времени года &quot;весна&quot;, &quot;лето&quot;, &quot;осень&quot;, &quot;зима&quot; определить погоду &quot;тепло&quot;, &quot;жарко&quot;, &quot;холодно&quot;, &quot;очень холодно&quot;. Я так...

Наследуемым классом для комплексного числа объявить класс "радиус-вектор", имеющий данные "длина" и "угол" - C++
кто то напишите пожалуйста, вот программа: наследуемым классом для комплексного числа объявить класс &quot;радиус-вектор&quot;, имеющий данные...

Ошибка "Unhandled exception, Access violation writing location" - C++
Пишу вот так: root-&gt;child1-&gt;parent=root; root-&gt;child2-&gt;parent=root;выходит ошибка Unhandled exception at 0x00073dec in Regul.exe:...

Непонятная ошибка "Access violation writing location 0xcdcdcdd5" - C++
#include &lt;iostream&gt; #include &lt;cstdlib&gt; struct Node{ int data; Node *next, *prev; }; typedef Node...

0
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
05.12.2011, 15:04
Привет! Вот еще темы с ответами:

Ошибка исполнения "Access violation writing location 0x.........." - C++
Здравствуйте! Написал код в MS Visual Studio 2012 64-битной такой код: #include &quot;stdafx.h&quot; #include &lt;iostream&gt; #include...

Ошибка компилятора: "Access violation writing location" - C++
Здравствуйте! Проблема в том что я пишу простой скрипт и у меня всегда вылезает окошко с надписью : Unhandled exception at 0X002611F1 in...

Ошибка "Access violation writing location" при работе с массивом. - C++
Задание номер 2 #include &lt;stdio.h&gt; #include &lt;cstdlib&gt; #include &lt;math.h&gt; #include &lt;cmath&gt; #include &lt;iostream&gt; #include...

Через ООП: Дать для числа наименование: "рубль", "рубля", "рублей"; - C++
Помогите пожалуйста с задачей. Могу сделать ее просто, но надо через ООП и у меня не получается. Дано натуральное число N (N&lt;20),...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
1
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.
Рейтинг@Mail.ru