Skip to content

Commit 43d505c

Browse files
committed
FrameEnumerator
1 parent ac9d248 commit 43d505c

File tree

5 files changed

+147
-35
lines changed

5 files changed

+147
-35
lines changed

FrameEnumerator.cpp

+71
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
2+
#include "FrameEnumerator.hpp"
3+
#include <cassert>
4+
#include <cstdio>
5+
6+
FrameEnumerator::FrameEnumerator(MediaDecoder* mediaDecoder, AVStream* stream)
7+
: mMediaDecoder(mediaDecoder),
8+
mStream(stream),
9+
mLastTimestamp(AV_NOPTS_VALUE),
10+
mLastIndex(-1),
11+
mFramePred(FramePredicate_KeyFrames)
12+
{
13+
if (mStream->nb_index_entries < mStream->nb_frames) {
14+
mMediaDecoder->seek(0);
15+
AVPacket pkt;
16+
while (true) {
17+
int ret = mMediaDecoder->readPacket(&pkt);
18+
av_free_packet(&pkt);
19+
if (ret == AVERROR_EOF) { break; }
20+
if (ret < 0) { break; }
21+
}
22+
}
23+
}
24+
25+
bool
26+
FrameEnumerator::moveNext()
27+
{
28+
assert(-1 <= mLastIndex);
29+
if (mLastIndex >= 0 &&
30+
(mStream->nb_index_entries <= mLastIndex || mStream->index_entries[mLastIndex].timestamp != mLastTimestamp)) {
31+
// The index has changed.
32+
// It seems that something to handle this situation should be implemented.
33+
assert(false);
34+
}
35+
36+
AVIndexEntry* entries = mStream->index_entries;
37+
int nIndexEntries = mStream->nb_index_entries;
38+
for (mLastIndex++; mLastIndex < nIndexEntries; ++mLastIndex) {
39+
AVIndexEntry* ent = &entries[mLastIndex];
40+
if (this->mFramePred(ent)) {
41+
mLastTimestamp = ent->timestamp;
42+
return true;
43+
}
44+
}
45+
46+
mLastIndex = nIndexEntries;
47+
mLastTimestamp = AV_NOPTS_VALUE;
48+
return false;
49+
}
50+
51+
void
52+
FrameEnumerator::reset()
53+
{
54+
mLastIndex = -1;
55+
mLastTimestamp = AV_NOPTS_VALUE;
56+
av_seek_frame(mMediaDecoder->getFormatContext(), -1, 0, 0);
57+
}
58+
59+
int
60+
FrameEnumerator::seek()
61+
{
62+
if (mLastIndex < 0) { return -1; }
63+
return mMediaDecoder->seekToIndex(mStream->index, mLastIndex);
64+
}
65+
66+
bool
67+
FrameEnumerator::FramePredicate_KeyFrames(const AVIndexEntry* indexEntry)
68+
{
69+
return 0 != (indexEntry->flags & AVINDEX_KEYFRAME);
70+
}
71+

FrameEnumerator.hpp

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
#ifndef FRAME_ENUMERATOR_H_
2+
#define FRAME_ENUMERATOR_H_
3+
4+
#include "MediaDecoder.hpp"
5+
#include "libav.hpp"
6+
#include <iterator>
7+
8+
class FrameEnumerator
9+
{
10+
public:
11+
typedef bool(*FramePredicate)(const AVIndexEntry*);
12+
13+
private:
14+
MediaDecoder* mMediaDecoder;
15+
AVStream* mStream;
16+
int64_t mLastTimestamp;
17+
int mLastIndex;
18+
19+
FramePredicate mFramePred;
20+
21+
public:
22+
FrameEnumerator(MediaDecoder* mediaDecoder, AVStream* stream);
23+
bool moveNext();
24+
int64_t timestamp() const { return mLastTimestamp; }
25+
int index() const { return mLastIndex; }
26+
void reset();
27+
28+
int seek();
29+
30+
private:
31+
static bool FramePredicate_KeyFrames(const AVIndexEntry* indexEntry);
32+
};
33+
34+
#endif

MediaDecoder.cpp

+30-24
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
#include "MediaDecoder.hpp"
22

3+
#include <cassert>
4+
35
void
46
MediaDecoder::initFfmpeg()
57
{
@@ -68,18 +70,18 @@ MediaDecoder::openFile(const char* filename)
6870
for (int i = 0; i < streamCount; ++i) {
6971
if (0 > (intRet = this->prepareStream(i))) {
7072
this->outputMessage(0, "prepareStream() failed: ret=%d", intRet);
71-
return intRet;
7273
}
7374
if (mFirstVideoStreamIndex == -1 && mFormatContext->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
7475
mFirstVideoStreamIndex = i;
7576
}
7677
}
7778

78-
if (mFirstVideoStreamIndex != -1) {
79-
AVCodecContext* codecContext = mFormatContext->streams[mFirstVideoStreamIndex]->codec;
80-
this->setScaleParameters(codecContext->width, codecContext->height, PIX_FMT_RGB32, Stride_4bytes);
81-
}
82-
79+
if (mFirstVideoStreamIndex != -1) {
80+
this->outputMessage(0, "Video stream is %d", mFirstVideoStreamIndex);
81+
AVCodecContext* codecContext = mFormatContext->streams[mFirstVideoStreamIndex]->codec;
82+
this->setScaleParameters(codecContext->width, codecContext->height, PIX_FMT_RGB32, Stride_4bytes);
83+
}
84+
8385
return 0;
8486
}
8587

@@ -117,6 +119,7 @@ MediaDecoder::setScaleParameters(int width, int height, PixelFormat pixelFormat,
117119
// SWS_BILINEAR,
118120
SWS_FAST_BILINEAR,
119121
NULL, NULL, NULL);
122+
120123
if (!mSwsContext) {
121124
this->outputMessage(0, "sws_getContext failed.");
122125
return -1;
@@ -147,32 +150,32 @@ MediaDecoder::setScaleParameters(int width, int height, PixelFormat pixelFormat,
147150
return 0;
148151
}
149152

153+
int
154+
MediaDecoder::seek(int streamIndex, int64_t timestamp)
155+
{
156+
return av_seek_frame(mFormatContext, streamIndex, timestamp, 0);
157+
}
158+
150159
int
151160
MediaDecoder::seek(double timestamp)
152161
{
153-
int intRet;
154-
int streamCount = this->getStreamCount();
155-
int failCount = 0;
156-
for (int i = 0; i < streamCount; ++i) {
157-
double timeBase = av_q2d(mFormatContext->streams[i]->time_base);
158-
int64_t ts = static_cast<int64_t>(timestamp / timeBase);
159-
intRet = av_seek_frame(mFormatContext, i, ts, 0);
160-
if (0 > intRet) {
161-
failCount ++;
162-
}
163-
}
164-
return failCount;
162+
return this->seek(-1, static_cast<uint64_t>(timestamp * AV_TIME_BASE));
165163
}
166164

167165
int
168166
MediaDecoder::seekToIndex(int streamIndex, int index) {
169167
AVStream* stream = this->getStream(streamIndex);
170-
if (!stream) { return -1; }
168+
if (!stream) {
169+
this->outputMessage(0, "Stream index %d not found.", streamIndex);
170+
return -1; }
171171

172172
AVIndexEntry* entries = stream->index_entries;
173-
if (!entries) { return -1; }
173+
if (!entries) {
174+
this->outputMessage(0, "Tried to seek by index, but there is no index entries.");
175+
return -1; }
174176

175-
if (0 < index || index <= stream->nb_index_entries) {
177+
if (index < 0 || stream->nb_index_entries <= index) {
178+
this->outputMessage(0, "Index out of bound: %d / %d", index, stream->nb_index_entries);
176179
return -1;
177180
}
178181

@@ -234,6 +237,10 @@ MediaDecoder::decodeVideoFrame(AVPacket* packet, AVFrame* outFrame, double* outT
234237
int
235238
MediaDecoder::scaleVideoFrame(AVFrame* frame, uint8_t* buffer, int bufferSize)
236239
{
240+
if (!mSwsContext) {
241+
this->outputMessage(0, "sws context is not initialized.");
242+
return -1; }
243+
237244
int intRet;
238245
uint8_t* data[] = { (uint8_t*)buffer, NULL, NULL, NULL };
239246
int lineSize[] = { mScaleStride, 0, 0, 0 };
@@ -279,7 +286,6 @@ MediaDecoder::decodeVideo(AVPacket* packet, uint8_t* buffer, int bufferSize, dou
279286
goto CLEANUP;
280287
}
281288

282-
283289
// scale and transform
284290
intRet = this->scaleVideoFrame(mFrame, buffer, bufferSize);
285291
if (intRet < 0) {
@@ -343,9 +349,9 @@ MediaDecoder::prepareStream(int streamIndex)
343349
AVStream* stream = mFormatContext->streams[streamIndex];
344350
AVCodecContext* codecContext = stream->codec;
345351
AVCodec* codec = avcodec_find_decoder(codecContext->codec_id);
346-
352+
347353
if (!codec) {
348-
this->outputMessage(0, "Failed to find decoder: codec_id=%d", codecContext->codec_id);
354+
this->outputMessage(0, "Failed to find decoder: streamIndex=%d codecId=%d codecType=%d", streamIndex, codecContext->codec_id, codecContext->codec_type);
349355
return -1;
350356
}
351357

MediaDecoder.hpp

+2-11
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,7 @@
11
#ifndef MEDIA_DECODER_H_
22
#define MEDIA_DECODER_H_
33

4-
#ifndef __STDC_CONSTANT_MACROS
5-
#define __STDC_CONSTANT_MACROS
6-
#endif
7-
8-
extern "C" {
9-
#include <libavutil/avutil.h>
10-
#include <libavformat/avformat.h>
11-
#include <libavcodec/avcodec.h>
12-
#include <libswscale/swscale.h>
13-
}
14-
4+
#include "libav.hpp"
155

166
typedef enum {
177
Stride_Tight,
@@ -82,6 +72,7 @@ class MediaDecoder
8272

8373
// decode
8474
int seek(double timestamp);
75+
int seek(int streamIndex, int64_t timestamp);
8576
int seekToIndex(int streamIndex, int index);
8677
int decodeAudio(AVPacket* packet, uint8_t* buffer, int bufferSize, double* outTimestamp, int* outDataSize);
8778
int decodeVideo(AVPacket* packet, uint8_t* buffer, int bufferSize, double thresholdTimestamp, double* outTimestamp, int* outDataSize, bool* outSkipped);

libav.hpp

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#ifndef __STDC_CONSTANT_MACROS
2+
#define __STDC_CONSTANT_MACROS
3+
#endif
4+
5+
extern "C" {
6+
#include <libavutil/avutil.h>
7+
#include <libavformat/avformat.h>
8+
#include <libavcodec/avcodec.h>
9+
#include <libswscale/swscale.h>
10+
}

0 commit comments

Comments
 (0)