在C++中将webM文件作为参数传递

Passing webM file as parameter in C++?

本文关键字:参数传递 文件 webM C++ 中将      更新时间:2023-10-16

我正在尝试编写一个程序,该程序接受webM文件(媒体)作为参数,然后通过TTY尽可能详细地输出流细节。我想我会尝试以二进制模式打开文件,但不确定从哪里开始。

谢谢你的帮助。

这听起来像是一个非常高级的问题,所以我会这样回答:

如果您在C/C++中创建一个需要接受参数的命令行程序,请查找如何将"argc"answers"argv"参数用于main()函数。

一旦参数被传递到主函数中,您将尝试使用一些文件读取库来打开它(根据您的需求和平台,有几种可供选择)。是的,如果文件库关心差异,您将希望以二进制模式打开WebM文件。如果使用fopen(),请指定"rb"以二进制模式读取——这在Unix上没有任何区别(与普通的"r"相比),但在Windows上会有很大区别。

从那里,您可以开始从WebM文件中读取字节并进行处理。请注意,WebM是基于Matroska多媒体格式,这是相当复杂的。如果你这样做是一种学术锻炼,那么你就会拥有更多的权力。如果你想在紧迫的最后期限内完成一些事情,你可以打电话给一些库来代表你完成Matroska解析的繁重工作。

您可以通过使用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("nnInput webm file = %s , Output webm file = %sn", 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 %sn", 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 filen");
    /** 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.%dn", maj, min, build, rev);
    ebmlHeader.Parse(mkvrdr, pos);
    printf("ttt    EBML Headern");
    printf("ttEBML Versiontt: %lldn", ebmlHeader.m_version);
    printf("ttEBML MaxIDLengtht: %lldn", ebmlHeader.m_maxIdLength);
    printf("ttEBML MaxSizeLengtht: %lldn", ebmlHeader.m_maxSizeLength);
    printf("ttDoc Typett: %sn", ebmlHeader.m_docType);
    printf("ttPosttt: %lldn", 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("ttt   Segment Infon");
    printf("ttTimeCodeScalett: %lld n", timeCodeScale);
    printf("ttDurationtt: %lldn", duration_ns);
    const double duration_sec = double(duration_ns) / 1000000000;
    printf("ttDuration(secs)tt: %7.3lfn", duration_sec);
    if (pTitle == NULL)
        printf("ttTrack Namett: NULLn");
    else 
    {
        printf("ttTrack Namett: %lsn", pTitle);
        delete[] pTitle;
    }    
    if (pMuxingApp == NULL)
        printf("ttMuxing Apptt: NULLn");
    else 
    {
        printf("ttMuxing Apptt: %lsn", pMuxingApp);
        delete[] pMuxingApp;
    }
    if (pWritingApp == NULL)
        printf("ttWriting Apptt: NULLn");
    else 
    {
        printf("ttWriting Apptt: %lsn", pWritingApp);
        delete[] pWritingApp;
    }
    // pos of segment payload
    printf("ttPosition(Segment)t: %lldn", pSegment->m_start);
    // size of segment payload
    printf("ttSize(Segment)tt: %lldn", pSegment->m_size);
    const mkvparser::Tracks* pTracks = pSegment->GetTracks();
    unsigned long track_num = 0;
    const unsigned long num_tracks = pTracks->GetTracksCount();
    printf("nttt   Track Infon");

    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("ttTrack Typett: %ldn", trackType);
        printf("ttTrack Numbertt: %ldn", trackNumber);
        printf("ttTrack Uidtt: %lldn", trackUid);
        if (pTrackName == NULL)
            printf("ttTrack Namett: NULLn");
        else 
        {
            printf("ttTrack Namett: %ls n", pTrackName);
            delete[] pTrackName;
        }
        const char* const pCodecId = pTrack->GetCodecId();
        if (pCodecId == NULL)
            printf("ttCodec Idtt: NULLn");
        else
            printf("ttCodec Idtt: %sn", pCodecId);
        const char* const pCodecName_ = pTrack->GetCodecNameAsUTF8();
        const wchar_t* const pCodecName = utf8towcs(pCodecName_);
        if (pCodecName == NULL)
            printf("ttCodec Namett: NULLn");
        else 
        {
            printf("ttCodec Namett: %lsn", pCodecName);
            delete[] pCodecName;
        }
        if (trackType == mkvparser::Track::kVideo) 
        {
            const VideoTrack* const pVideoTrack =
            static_cast<const VideoTrack*>(pTrack);
            const long long width = pVideoTrack->GetWidth();
            printf("ttVideo Widthtt: %lldn", width);
            const long long height = pVideoTrack->GetHeight();
            printf("ttVideo Heighttt: %lldn", height);
            const double rate = pVideoTrack->GetFrameRate();
            printf("ttVideo Ratett: %fn", rate);
        }
        if (trackType == mkvparser::Track::kAudio) 
        {
            const AudioTrack* const pAudioTrack =
            static_cast<const AudioTrack*>(pTrack);
            const long long channels = pAudioTrack->GetChannels();
            printf("ttAudio Channelstt: %lldn", channels);
            const long long bitDepth = pAudioTrack->GetBitDepth();
            printf("ttAudio BitDepthtt: %lldn", bitDepth);
            const double sampleRate = pAudioTrack->GetSamplingRate();
            printf("ttAddio Sample Ratet: %.3fn", sampleRate);
            const long long codecDelay = pAudioTrack->GetCodecDelay();
            printf("ttAudio Codec Delayt: %lldn", codecDelay);
            const long long seekPreRoll = pAudioTrack->GetSeekPreRoll();
            printf("ttAudio Seek Pre Rollt: %lldn", seekPreRoll);
        }
    }

    printf("nnttt   Cluster Infon");
    const unsigned long clusterCount = pSegment->GetCount();
    printf("ttCluster Countt: %ldnn", clusterCount);
    if (clusterCount == 0) 
    {
        printf("ttSegment has no clusters.n");
        return -1;
    }
    const mkvparser::Cluster* pCluster = pSegment->GetFirst();
    while ((pCluster != NULL) && !pCluster->EOS()) 
    {
        const long long timeCode = pCluster->GetTimeCode();
        printf("ttCluster Time Codet: %lldn", timeCode);
        const long long time_ns = pCluster->GetTime();
        printf("ttCluster Time (ns)t: %lldn", time_ns);
        const BlockEntry* pBlockEntry;
        long status = pCluster->GetFirst(pBlockEntry);
        if (status < 0)  // error
        {
            printf("ttError parsing first block of clustern");
            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("tttBlocktt:UNKNOWN TRACK TYPEn");
            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("tttBlocktt:%s,%s,%15lld,%lldn",
                (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("ttt %15ld,%15llxn", size, offset);
                }
            }
            status = pCluster->GetNext(pBlockEntry, pBlockEntry);
            if (status < 0) 
            {
                printf("tttError parsing next block of clustern");
                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("ttCuesn");
        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(
                        "tttCue Point %4d Track %3lu(%c) Time %14lld "
                        "Block %4lld Pos %8llxn",
                        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("ttTagsn");
        for (int i = 0; i < tags->GetTagCount(); ++i) 
        {
            const mkvparser::Tags::Tag* const tag = tags->GetTag(i);
            printf("tttTagn");
            for (int j = 0; j < tag->GetSimpleTagCount(); j++) 
            {
                const mkvparser::Tags::SimpleTag* const simple_tag =
                    tag->GetSimpleTag(j);
                printf("ttttSimple 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'';
    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;
}