我正在尝试编写一个程序,该程序接受webM文件(媒体)作为参数,然后通过TTY尽可能详细地输出流细节。我想我会尝试以二进制模式打开文件,但不确定从哪里开始。
谢谢你的帮助。
这听起来像是一个非常高级的问题,所以我会这样回答:
如果您在C/C++中创建一个需要接受参数的命令行程序,请查找如何将"argc"one_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;
}