Передача файла WebM в качестве параметра в C ++? - PullRequest
0 голосов
/ 12 марта 2012

Я пытаюсь написать программу, которая принимает файл webM (медиа) в качестве параметра, а затем выводит детали потока через TTY как можно более подробно.Я подумал, что попробую открыть файл в двоичном режиме, но не уверен, с чего начать.

Спасибо за помощь.

Ответы [ 2 ]

1 голос
/ 23 июля 2015

Вы можете сделать это, используя libwebm. Пример кода приведен ниже. Он печатает заголовок, кластер, сегменты и т. Д.

main.cpp

#include "stdio.h"
#include "stdlib.h"
#include "stdbool.h"
#include "string.h"

#include <memory>
#include <mkv/mkvreader.hpp>
#include <mkv/mkvparser.hpp>
#include <mkv/mkvparser.hpp>
#include "webm_parser.h"

static const wchar_t* utf8towcs(const char* str);
bool InputHasCues(const mkvparser::Segment* const segment);

using namespace mkvparser;

/**
* This file reads an webm file. Generates a new file with random number 
* of packets in a single webm page.
*/
int webm_parse(int argc, char **argv)
{
    int ret = -1;
    char *file_out;
    char *file_in;
    FILE *fd_out = NULL;
    MkvReader reader;

    if(argc != 3)
    {
        printf("Usage: ./webm <input webm file> <output webm file>\n");
        exit(0);
    }

    file_in = argv[1];
    file_out = argv[2];

    printf("\n\nInput webm file = %s , Output webm file = %s\n", file_in, file_out);

    fd_out = fopen(file_out, "w+");
    if(fd_out == NULL) goto on_error;

    if(reader.Open(file_in))
    {
        printf("Error opening input file %s", file_in);
    }
    else
    {
        printf("Successfully opened input file %s\n", file_in);
    }

    webm_parse_header(&reader);

    /** Return 0 on success */
    printf("\n");
    return ret;

on_error:
    if(fd_out) fclose(fd_out);
    printf("Error while parse/generate webm file\n");

    /** Return -1 on failure */
    return -1;
}

int webm_parse_header(void *reader)
{
    int maj, min, build, rev;
    long long pos = 0;
    typedef mkvparser::Segment seg_t;
    seg_t* pSegment_;
    long long ret;
    MkvReader *mkvrdr = (MkvReader *)reader;
    EBMLHeader ebmlHeader;

    GetVersion(maj, min, build, rev);
    printf("libmkv verison: %d.%d.%d.%d\n", maj, min, build, rev);
    ebmlHeader.Parse(mkvrdr, pos);

    printf("\t\t\t    EBML Header\n");
    printf("\t\tEBML Version\t\t: %lld\n", ebmlHeader.m_version);
    printf("\t\tEBML MaxIDLength\t: %lld\n", ebmlHeader.m_maxIdLength);
    printf("\t\tEBML MaxSizeLength\t: %lld\n", ebmlHeader.m_maxSizeLength);
    printf("\t\tDoc Type\t\t: %s\n", ebmlHeader.m_docType);
    printf("\t\tPos\t\t\t: %lld\n", pos);    

    ret = seg_t::CreateInstance(mkvrdr, pos, pSegment_);
    if (ret) 
    {
        printf("Segment::CreateInstance() failed.\n");
        return -1;
    }
    else
    {
        printf("Segment::CreateInstance() successful.\n");
    }

    const std::auto_ptr<seg_t> pSegment(pSegment_);
    ret = pSegment->Load();
    if (ret < 0) 
    {
        printf("Segment::Load() failed.\n");
        return -1;
    }
    else
    {
        printf("Segment::Load() successful.\n");
    }

    const SegmentInfo* const pSegmentInfo = pSegment->GetInfo();
    const long long timeCodeScale = pSegmentInfo->GetTimeCodeScale();
    const long long duration_ns = pSegmentInfo->GetDuration();
    const char* const pTitle_ = pSegmentInfo->GetTitleAsUTF8();
    const wchar_t* const pTitle = utf8towcs(pTitle_);
    const char* const pMuxingApp_ = pSegmentInfo->GetMuxingAppAsUTF8();
    const wchar_t* const pMuxingApp = utf8towcs(pMuxingApp_);
    const char* const pWritingApp_ = pSegmentInfo->GetWritingAppAsUTF8();
    const wchar_t* const pWritingApp = utf8towcs(pWritingApp_);

    printf("\n");
    printf("\t\t\t   Segment Info\n");
    printf("\t\tTimeCodeScale\t\t: %lld \n", timeCodeScale);
    printf("\t\tDuration\t\t: %lld\n", duration_ns);

    const double duration_sec = double(duration_ns) / 1000000000;
    printf("\t\tDuration(secs)\t\t: %7.3lf\n", duration_sec);

    if (pTitle == NULL)
        printf("\t\tTrack Name\t\t: NULL\n");
    else 
    {
        printf("\t\tTrack Name\t\t: %ls\n", pTitle);
        delete[] pTitle;
    }    

    if (pMuxingApp == NULL)
        printf("\t\tMuxing App\t\t: NULL\n");
    else 
    {
        printf("\t\tMuxing App\t\t: %ls\n", pMuxingApp);
        delete[] pMuxingApp;
    }

    if (pWritingApp == NULL)
        printf("\t\tWriting App\t\t: NULL\n");
    else 
    {
        printf("\t\tWriting App\t\t: %ls\n", pWritingApp);
        delete[] pWritingApp;
    }

    // pos of segment payload
    printf("\t\tPosition(Segment)\t: %lld\n", pSegment->m_start);

    // size of segment payload
    printf("\t\tSize(Segment)\t\t: %lld\n", pSegment->m_size);

    const mkvparser::Tracks* pTracks = pSegment->GetTracks();

    unsigned long track_num = 0;
    const unsigned long num_tracks = pTracks->GetTracksCount();

    printf("\n\t\t\t   Track Info\n");


    while (track_num != num_tracks) 
    {
        const Track* const pTrack = pTracks->GetTrackByIndex(track_num++);

        if (pTrack == NULL)
        continue;

        const long trackType = pTrack->GetType();
        const long trackNumber = pTrack->GetNumber();
        const unsigned long long trackUid = pTrack->GetUid();
        const wchar_t* const pTrackName = utf8towcs(pTrack->GetNameAsUTF8());

        printf("\t\tTrack Type\t\t: %ld\n", trackType);
        printf("\t\tTrack Number\t\t: %ld\n", trackNumber);
        printf("\t\tTrack Uid\t\t: %lld\n", trackUid);

        if (pTrackName == NULL)
            printf("\t\tTrack Name\t\t: NULL\n");
        else 
        {
            printf("\t\tTrack Name\t\t: %ls \n", pTrackName);
            delete[] pTrackName;
        }

        const char* const pCodecId = pTrack->GetCodecId();

        if (pCodecId == NULL)
            printf("\t\tCodec Id\t\t: NULL\n");
        else
            printf("\t\tCodec Id\t\t: %s\n", pCodecId);

        const char* const pCodecName_ = pTrack->GetCodecNameAsUTF8();
        const wchar_t* const pCodecName = utf8towcs(pCodecName_);

        if (pCodecName == NULL)
            printf("\t\tCodec Name\t\t: NULL\n");
        else 
        {
            printf("\t\tCodec Name\t\t: %ls\n", pCodecName);
            delete[] pCodecName;
        }

        if (trackType == mkvparser::Track::kVideo) 
        {
            const VideoTrack* const pVideoTrack =
            static_cast<const VideoTrack*>(pTrack);

            const long long width = pVideoTrack->GetWidth();
            printf("\t\tVideo Width\t\t: %lld\n", width);

            const long long height = pVideoTrack->GetHeight();
            printf("\t\tVideo Height\t\t: %lld\n", height);

            const double rate = pVideoTrack->GetFrameRate();
            printf("\t\tVideo Rate\t\t: %f\n", rate);
        }

        if (trackType == mkvparser::Track::kAudio) 
        {
            const AudioTrack* const pAudioTrack =
            static_cast<const AudioTrack*>(pTrack);

            const long long channels = pAudioTrack->GetChannels();
            printf("\t\tAudio Channels\t\t: %lld\n", channels);

            const long long bitDepth = pAudioTrack->GetBitDepth();
            printf("\t\tAudio BitDepth\t\t: %lld\n", bitDepth);

            const double sampleRate = pAudioTrack->GetSamplingRate();
            printf("\t\tAddio Sample Rate\t: %.3f\n", sampleRate);

            const long long codecDelay = pAudioTrack->GetCodecDelay();
            printf("\t\tAudio Codec Delay\t: %lld\n", codecDelay);

            const long long seekPreRoll = pAudioTrack->GetSeekPreRoll();
            printf("\t\tAudio Seek Pre Roll\t: %lld\n", seekPreRoll);
        }
    }


    printf("\n\n\t\t\t   Cluster Info\n");
    const unsigned long clusterCount = pSegment->GetCount();

    printf("\t\tCluster Count\t: %ld\n\n", clusterCount);

    if (clusterCount == 0) 
    {
        printf("\t\tSegment has no clusters.\n");
        return -1;
    }

    const mkvparser::Cluster* pCluster = pSegment->GetFirst();

    while ((pCluster != NULL) && !pCluster->EOS()) 
    {
        const long long timeCode = pCluster->GetTimeCode();
        printf("\t\tCluster Time Code\t: %lld\n", timeCode);

        const long long time_ns = pCluster->GetTime();
        printf("\t\tCluster Time (ns)\t: %lld\n", time_ns);

        const BlockEntry* pBlockEntry;

        long status = pCluster->GetFirst(pBlockEntry);

        if (status < 0)  // error
        {
            printf("\t\tError parsing first block of cluster\n");
            fflush(stdout);
            return -1;
        }

        while ((pBlockEntry != NULL) && !pBlockEntry->EOS()) 
        {
            const Block* const pBlock = pBlockEntry->GetBlock();
            const long long trackNum = pBlock->GetTrackNumber();
            const unsigned long tn = static_cast<unsigned long>(trackNum);
            const Track* const pTrack = pTracks->GetTrackByNumber(tn);

            if (pTrack == NULL)
                printf("\t\t\tBlock\t\t:UNKNOWN TRACK TYPE\n");
            else 
            {
                const long long trackType = pTrack->GetType();
                const int frameCount = pBlock->GetFrameCount();
                const long long time_ns = pBlock->GetTime(pCluster);
                const long long discard_padding = pBlock->GetDiscardPadding();

                printf("\t\t\tBlock\t\t:%s,%s,%15lld,%lld\n",
                (trackType == mkvparser::Track::kVideo) ? "V" : "A",
                pBlock->IsKey() ? "I" : "P", time_ns, discard_padding);

                for (int i = 0; i < frameCount; ++i) 
                {
                    const Block::Frame& theFrame = pBlock->GetFrame(i);
                    const long size = theFrame.len;
                    const long long offset = theFrame.pos;
                    printf("\t\t\t %15ld,%15llx\n", size, offset);
                }
            }

            status = pCluster->GetNext(pBlockEntry, pBlockEntry);

            if (status < 0) 
            {
                printf("\t\t\tError parsing next block of cluster\n");
                fflush(stdout);
                return -1;
            }
        }
        pCluster = pSegment->GetNext(pCluster);
    }

    if (InputHasCues(pSegment.get())) 
    {
        // Walk them.
        const mkvparser::Cues* const cues = pSegment->GetCues();
        const mkvparser::CuePoint* cue = cues->GetFirst();
        int cue_point_num = 1;

        printf("\t\tCues\n");
        do 
        {
            for (track_num = 0; track_num < num_tracks; ++track_num) 
            {
                const mkvparser::Track* const track =
                        pTracks->GetTrackByIndex(track_num);

                const mkvparser::CuePoint::TrackPosition* const track_pos =
                        cue->Find(track);

                if (track_pos != NULL) 
                {
                    const char track_type =
                    (track->GetType() == mkvparser::Track::kVideo) ? 'V' : 'A';
                    printf(
                        "\t\t\tCue Point %4d Track %3lu(%c) Time %14lld "
                        "Block %4lld Pos %8llx\n",
                        cue_point_num, track->GetNumber(), track_type,
                        cue->GetTime(pSegment.get()), track_pos->m_block,
                        track_pos->m_pos);
                }
            }
            cue = cues->GetNext(cue);
            ++cue_point_num;

        } while (cue != NULL);
    }

    const mkvparser::Tags* const tags = pSegment->GetTags();
    if (tags && tags->GetTagCount() > 0) 
    {
        printf("\t\tTags\n");
        for (int i = 0; i < tags->GetTagCount(); ++i) 
        {
            const mkvparser::Tags::Tag* const tag = tags->GetTag(i);
            printf("\t\t\tTag\n");
            for (int j = 0; j < tag->GetSimpleTagCount(); j++) 
            {
                const mkvparser::Tags::SimpleTag* const simple_tag =
                    tag->GetSimpleTag(j);
                printf("\t\t\t\tSimple Tag \"%s\" Value \"%s\"\n",
                    simple_tag->GetTagName(), simple_tag->GetTagString());
            }
        }
    }

    fflush(stdout);
    return 0;

on_error:
    return -1;
}

static const wchar_t* utf8towcs(const char* str) 
{
    if (str == NULL)
        return NULL;

    // TODO: this probably requires that the locale be
    // configured somehow:

    const size_t size = mbstowcs(NULL, str, 0);

    if (size == 0)
        return NULL;

    wchar_t* const val = new wchar_t[size + 1];

    mbstowcs(val, str, size);
    val[size] = L'\0';

    return val;
}

bool InputHasCues(const mkvparser::Segment* const segment) 
{
    const mkvparser::Cues* const cues = segment->GetCues();
    if (cues == NULL)
        return false;

    while (!cues->DoneParsing())
        cues->LoadCuePoint();

    const mkvparser::CuePoint* const cue_point = cues->GetFirst();
    if (cue_point == NULL)
        return false;

    return true;
}
1 голос
/ 12 марта 2012

Звучит как вопрос очень высокого уровня, поэтому я отвечу на него так:

Если вы создаете программу на C / C ++ для командной строки, которая должна принимать параметры, посмотрите, как использовать параметры 'argc' и 'argv' для функции main ().

Как только вы передадите параметр в вашу основную функцию, вы попытаетесь открыть его с помощью некоторой библиотеки для чтения файлов (есть несколько вариантов на выбор в зависимости от ваших потребностей и платформы). Да, вы захотите открыть файл WebM в двоичном режиме, если файловая библиотека заботится о разнице. Если вы используете fopen (), укажите «rb» для чтения в двоичном режиме - это не будет иметь никакого значения для Unix (по сравнению с обычным «r»), но будет иметь большое значение для Windows.

Оттуда вы можете начать чтение байтов из файла WebM и их обработку. Имейте в виду, что WebM основан на мультимедийном формате Matroska, который является довольно сложным. Если вы делаете это как учебное упражнение, больше сил для вас. Если вы хотите, чтобы что-то было выполнено в сжатые сроки, есть библиотеки, к которым вы можете обратиться, чтобы выполнить тяжелый анализ Matroska от вашего имени.

...