librtmp пример c програмиране?

Здравейте момчета, аз съм нов в програмирането на c и бих искал да знам дали някой има наистина прост пример за отваряне на .flv файл и изпращане до wowza сървър с помощта на librtmp.

Намерих много код, който може да се свърже с помощта на библиотеката, но не много при публикуване на flv.

По принцип:

init librtmp -> активиране на запис -> свързване -> пакетиране на flv -> изпращане на пакети до завършване

РЕДАКТИРАНЕ:

Добре, така че първо трябва да отворя своя flv файл и да изолирам всеки пакет във flv файла, за да го изпратя на librtmp. Досега намерих този код:

https://github.com/noirotm/flvmeta/blob/master/src/flv.c


person Adrian M Cavazos    schedule 15.07.2014    source източник


Отговори (2)


Това е авторът на FLVMeta тук.

Може да искате да погледнете моя отговор на този въпрос: https://stackoverflow.com/a/13803143/393701

В допълнение към тази информация, мога да обясня някои части от C++ софтуер, който написах (за съжаление не е с отворен код за момента), чиято цел е да предава FLV файлове към RTMP сървър.

Това е тествано и работи добре с Wowza, nginx-rtmp, както и със сървъра за стрийминг на живо Dailymotion.

Инициализиране

std::string rtmp_url = "rtmp://server/app/stream";
// add this if doing live streaming:
rtmp_url.append(" live=1");

RTMP * rtmp = RTMP_Alloc();
if (!rtmp) {
    std::cerr << "Unable to create rtmp object\n";
    return;
}

RTMP_Init(rtmp);
RTMP_LogSetLevel(RTMP_LOGINFO);
RTMP_LogSetOutput(stderr);
RTMP_SetupURL(rtmp, const_cast<char*>(rtmp_url.c_str())); // librtmp is a mess
RTMP_EnableWrite(rtmp);

Странното const_cast се дължи на факта, че librtmp е проектиран странно и използва неконстантен char * като URL, въпреки че може да не е модифициран в действителност от библиотеката.
Освен това буферът ще се използва за докато RTMP обектът живее, така че низът не трябва да се освобождава преди изтриването на RTMP обекта.

Свързване

// connect to server
if (!RTMP_Connect(rtmp, NULL)) {
    std::cerr << "Unable to connect to server\n";
    RTMP_Free(rtmp);
    return;
}

Вторият аргумент на RTMP_Connect е незадължителен указател към RTMP пакет, който да се изпрати като параметър към връзката вместо пакета за връзка по подразбиране, изпратен от librtmp. Това обикновено не трябва да се използва при свързване към „нормални“ RTMP сървъри.

// connect to stream (this will be the stream specified in the RTMP URL)
if (!RTMP_ConnectStream(rtmp, 0)) {
    cerr << "Unable to connect to stream\n";
    RTMP_Free(rtmp);
    return;
}

Вторият аргумент на RTMP_ConnectStream е цяло число, представляващо клеймото за време, към което да се търси при възпроизвеждане на видеоклип. Когато публикувате, използването на 0 е безопасен залог.

Публикуване на пакети

Този раздел предполага използването на FLV кода, намерен в проекта FLVMeta (вижте https://github.com/noirotm/flvmeta/blob/master/src/flv.h#L175).

flv_stream * flvin = flv_open(input_file.c_str());
if (!flvin) {
    std::cerr << "Unable to open " << input_file << '\n';
    return;
}

Първо, добра идея е да се уверите, че сме отворили истински FLV файл.

flv_header header;
int res = flv_read_header(flvin, &header);
if (res == FLV_ERROR_NO_FLV || res == FLV_ERROR_EOF) {
    std::cerr << "Input file is not an FLV video\n";
    flv_close(flvin);
    return;
}

Сега прочетете всеки таг във файла и ги изпратете на RTMP сървъра.

// 10 MB copy buffer should be enough
#define BUFFER_SIZE 10000000
char buffer[BUFFER_SIZE];

flv_tag tag;
while (flv_read_tag(flvin, &tag) != FLV_ERROR_EOF) {
    // copy tag header
    flv_copy_tag(buffer, &tag, FLVSTREAMER_BUFFER_SIZE);

    // copy tag body
    size_t data_size = flv_read_tag_body(flvin, buffer + FLV_TAG_SIZE, BUFFER_SIZE - FLV_TAG_SIZE);

    // copy previous tag size
    uint32 pts;
    flv_read_prev_tag_size(flvin, &pts);
    flv_copy_prev_tag_size(
        buffer + FLV_TAG_SIZE + flv_tag_get_body_length(tag),
        pts,
        BUFFER_SIZE - (FLV_TAG_SIZE + flv_tag_get_body_length(tag))
    );

    // write the packet
    int size = FLV_TAG_SIZE + data_size + sizeof(uint32);
    if (RTMP_Write(rtmp, buffer, size) <= 0) {
        std::cerr << "Unable to write to server" << endl;
        break;
    }
}

Различните flv_* функции се грижат за справянето със спецификите на FLV формата, например проблеми с endianness и евентуално неправилно формиране на данни, така че бих препоръчал да ги използвате, ако вашата програма е съвместима с GPL лиценза.
Ако не, тя не е сложно да се използва стандартен I/O за итерация през тагове, стига FLV форматът да се разбира добре.

Също така е важно да се отбележи, че заглавката на FLV файла не трябва да се изпраща. librtmp ще открие всеки опит за изпращане на FLV хедъра и ще го предотврати.

Не е задължително да четете входящи RTMP пакети, докато публикувате, но ако искате да боравите правилно с протокола, се препоръчва подходът, използван от @szatmary в неговия код.

Друг важен аспект, който не се разглежда тук, е, че при публикуване на поток на живо е задължително да се приложи някаква форма на дроселиране, за да се изпращат данни с номиналния битрейт на видеото, в противен случай RTMP сървърът ще пропусне пакети и възпроизвеждането на видео ще пострада много.
Често срещан подход за решаване на този проблем може да бъде четене на времевия печат на всеки етикет и заспиване, ако пишем твърде бързо.

Почистване

flv_close(flvin);
RTMP_Free(rtmp);

Функцията RTMP_Free ще се погрижи за затварянето на потока, връзката и освобождаването на всяка разпределена памет.

person SirDarius    schedule 10.08.2014
comment
Благодаря ви много, търсих c код, но обяснението работи сега ме кара да съм на прав път :) - person Adrian M Cavazos; 12.08.2014
comment
@SirDarius Търся пример за RTMP сървър, как работи с вашия горен код на cpp клиент? - person AJit; 18.03.2018
comment
@AJit Това изглежда не е в обхвата на този въпрос. Искате ли да напишете RTMP сървър от нулата? librtmp е само библиотека от страна на клиента. - person SirDarius; 28.03.2018
comment
Да, @SirDarius, в крайна сметка се свързах и стриймвах през FFMPEG. - person AJit; 29.03.2018

Ето един много прост пример, който написах на C++ https://github.com/szatmary/RtmpBroadcaster/blob/master/rtmp.cpp

person szatmary    schedule 15.07.2014
comment
как ще отворите flv файла и ще използвате тази функция? sendTag(FlvTag &етикет) - person Adrian M Cavazos; 15.07.2014
comment
Вижте останалата част от проекта RtmpBroadcaster в git hub. Това е цялостно решение. - person szatmary; 15.07.2014
comment
Благодаря за отговора на въпроса ми, бихте ли ме насочили в правилната посока, като гледам кода ви, предполагам, че първо трябва да се запозная с flv и как да чета структурата на данните, за да я използвам с librtmp. Прав ли съм? имате ли някакъв url или откъде да започнете? - person Adrian M Cavazos; 15.07.2014
comment
adobe.com/content/dam/Adobe/ en/devnet/flv/pdfs/ - person szatmary; 15.07.2014