2012-03-11 24 views
0

我正在尝试编写一个接受webM文件(媒体)作为参数的程序,然后通过TTY以尽可能详细的方式输出流详细信息。我想我会尝试以二进制模式打开文件,但不知道从哪里开始。在C++中传递webM文件作为参数?

感谢您的帮助。

回答

1

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

如果你在一个需要接受参数C/C++创建一个命令行程序,查找如何使用main()函数的'argc'和'argv'参数。

将参数传递到主函数后,您将尝试使用某个文件读取库(根据您的需要和平台有多种选择)来打开它。是的,如果文件库关心区别,您将需要以二进制模式打开WebM文件。如果使用fopen(),指定“rb”以二进制模式读取 - 这在Unix上不会有任何区别(对比简单的“r”),但它会对Windows产生很大的影响。

从那里,您可以开始从WebM文件读取字节并处理它们。请注意,WebM是基于Matroska多媒体格式的,这个格式非常重要。如果你正在做这个学术练习,那么你的权力就更大了。如果您希望在紧迫的截止日期前完成某项工作,您可以调用一些库来代表您为Matroska解析而繁重的工作。

1

您可以通过使用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; 
}