decoder.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699
  1. #include "decoder.h"
  2. #include <c10/util/Logging.h>
  3. #include <libavutil/avutil.h>
  4. #include <future>
  5. #include <iostream>
  6. #include <mutex>
  7. #include "audio_stream.h"
  8. #include "cc_stream.h"
  9. #include "subtitle_stream.h"
  10. #include "util.h"
  11. #include "video_stream.h"
  12. namespace ffmpeg {
  13. namespace {
  14. constexpr size_t kIoBufferSize = 96 * 1024;
  15. constexpr size_t kIoPaddingSize = AV_INPUT_BUFFER_PADDING_SIZE;
  16. constexpr size_t kLogBufferSize = 1024;
  17. bool mapFfmpegType(AVMediaType media, MediaType* type) {
  18. switch (media) {
  19. case AVMEDIA_TYPE_AUDIO:
  20. *type = TYPE_AUDIO;
  21. return true;
  22. case AVMEDIA_TYPE_VIDEO:
  23. *type = TYPE_VIDEO;
  24. return true;
  25. case AVMEDIA_TYPE_SUBTITLE:
  26. *type = TYPE_SUBTITLE;
  27. return true;
  28. case AVMEDIA_TYPE_DATA:
  29. *type = TYPE_CC;
  30. return true;
  31. default:
  32. return false;
  33. }
  34. }
  35. std::unique_ptr<Stream> createStream(
  36. MediaType type,
  37. AVFormatContext* ctx,
  38. int idx,
  39. bool convertPtsToWallTime,
  40. const FormatUnion& format,
  41. int64_t loggingUuid) {
  42. switch (type) {
  43. case TYPE_AUDIO:
  44. return std::make_unique<AudioStream>(
  45. ctx, idx, convertPtsToWallTime, format.audio);
  46. case TYPE_VIDEO:
  47. return std::make_unique<VideoStream>(
  48. // negative loggingUuid indicates video streams.
  49. ctx,
  50. idx,
  51. convertPtsToWallTime,
  52. format.video,
  53. -loggingUuid);
  54. case TYPE_SUBTITLE:
  55. return std::make_unique<SubtitleStream>(
  56. ctx, idx, convertPtsToWallTime, format.subtitle);
  57. case TYPE_CC:
  58. return std::make_unique<CCStream>(
  59. ctx, idx, convertPtsToWallTime, format.subtitle);
  60. default:
  61. return nullptr;
  62. }
  63. }
  64. } // Namespace
  65. /* static */
  66. void Decoder::logFunction(void* avcl, int level, const char* cfmt, va_list vl) {
  67. if (!avcl) {
  68. // Nothing can be done here
  69. return;
  70. }
  71. AVClass* avclass = *reinterpret_cast<AVClass**>(avcl);
  72. if (!avclass) {
  73. // Nothing can be done here
  74. return;
  75. }
  76. Decoder* decoder = nullptr;
  77. if (strcmp(avclass->class_name, "AVFormatContext") == 0) {
  78. AVFormatContext* context = reinterpret_cast<AVFormatContext*>(avcl);
  79. if (context) {
  80. decoder = reinterpret_cast<Decoder*>(context->opaque);
  81. }
  82. } else if (strcmp(avclass->class_name, "AVCodecContext") == 0) {
  83. AVCodecContext* context = reinterpret_cast<AVCodecContext*>(avcl);
  84. if (context) {
  85. decoder = reinterpret_cast<Decoder*>(context->opaque);
  86. }
  87. } else if (strcmp(avclass->class_name, "AVIOContext") == 0) {
  88. AVIOContext* context = reinterpret_cast<AVIOContext*>(avcl);
  89. // only if opaque was assigned to Decoder pointer
  90. if (context && context->read_packet == Decoder::readFunction) {
  91. decoder = reinterpret_cast<Decoder*>(context->opaque);
  92. }
  93. } else if (strcmp(avclass->class_name, "SWResampler") == 0) {
  94. // expect AVCodecContext as parent
  95. if (avclass->parent_log_context_offset) {
  96. AVClass** parent =
  97. *(AVClass***)(((uint8_t*)avcl) + avclass->parent_log_context_offset);
  98. AVCodecContext* context = reinterpret_cast<AVCodecContext*>(parent);
  99. if (context) {
  100. decoder = reinterpret_cast<Decoder*>(context->opaque);
  101. }
  102. }
  103. } else if (strcmp(avclass->class_name, "SWScaler") == 0) {
  104. // cannot find a way to pass context pointer through SwsContext struct
  105. } else {
  106. VLOG(2) << "Unknown context class: " << avclass->class_name;
  107. }
  108. if (decoder != nullptr && decoder->enableLogLevel(level)) {
  109. char buf[kLogBufferSize] = {0};
  110. // Format the line
  111. int* prefix = decoder->getPrintPrefix();
  112. *prefix = 1;
  113. av_log_format_line(avcl, level, cfmt, vl, buf, sizeof(buf) - 1, prefix);
  114. // pass message to the decoder instance
  115. std::string msg(buf);
  116. decoder->logCallback(level, msg);
  117. }
  118. }
  119. bool Decoder::enableLogLevel(int level) const {
  120. return ssize_t(level) <= params_.logLevel;
  121. }
  122. void Decoder::logCallback(int level, const std::string& message) {
  123. LOG(INFO) << "Msg, uuid=" << params_.loggingUuid << " level=" << level
  124. << " msg=" << message;
  125. }
  126. /* static */
  127. int Decoder::shutdownFunction(void* ctx) {
  128. Decoder* decoder = (Decoder*)ctx;
  129. if (decoder == nullptr) {
  130. return 1;
  131. }
  132. return decoder->shutdownCallback();
  133. }
  134. int Decoder::shutdownCallback() {
  135. return interrupted_ ? 1 : 0;
  136. }
  137. /* static */
  138. int Decoder::readFunction(void* opaque, uint8_t* buf, int size) {
  139. Decoder* decoder = reinterpret_cast<Decoder*>(opaque);
  140. if (decoder == nullptr) {
  141. return 0;
  142. }
  143. return decoder->readCallback(buf, size);
  144. }
  145. /* static */
  146. int64_t Decoder::seekFunction(void* opaque, int64_t offset, int whence) {
  147. Decoder* decoder = reinterpret_cast<Decoder*>(opaque);
  148. if (decoder == nullptr) {
  149. return -1;
  150. }
  151. return decoder->seekCallback(offset, whence);
  152. }
  153. int Decoder::readCallback(uint8_t* buf, int size) {
  154. return seekableBuffer_.read(buf, size, params_.timeoutMs);
  155. }
  156. int64_t Decoder::seekCallback(int64_t offset, int whence) {
  157. return seekableBuffer_.seek(offset, whence, params_.timeoutMs);
  158. }
  159. /* static */
  160. void Decoder::initOnce() {
  161. static std::once_flag flagInit;
  162. std::call_once(flagInit, []() {
  163. #if LIBAVUTIL_VERSION_MAJOR < 56 // Before FFMPEG 4.0
  164. av_register_all();
  165. avcodec_register_all();
  166. #endif
  167. avformat_network_init();
  168. av_log_set_callback(Decoder::logFunction);
  169. av_log_set_level(AV_LOG_ERROR);
  170. VLOG(1) << "Registered ffmpeg libs";
  171. });
  172. }
  173. Decoder::Decoder() {
  174. initOnce();
  175. }
  176. Decoder::~Decoder() {
  177. cleanUp();
  178. }
  179. // Initialise the format context that holds information about the container and
  180. // fill it with minimal information about the format (codecs are not opened
  181. // here). Function reads in information about the streams from the container
  182. // into inputCtx and then passes it to decoder::openStreams. Finally, if seek is
  183. // specified within the decoder parameters, it seeks into the correct frame
  184. // (note, the seek defined here is "precise" seek).
  185. bool Decoder::init(
  186. const DecoderParameters& params,
  187. DecoderInCallback&& in,
  188. std::vector<DecoderMetadata>* metadata) {
  189. cleanUp();
  190. if ((params.uri.empty() || in) && (!params.uri.empty() || !in)) {
  191. LOG(ERROR)
  192. << "uuid=" << params_.loggingUuid
  193. << " either external URI gets provided or explicit input callback";
  194. return false;
  195. }
  196. // set callback and params
  197. params_ = params;
  198. if (!(inputCtx_ = avformat_alloc_context())) {
  199. LOG(ERROR) << "uuid=" << params_.loggingUuid
  200. << " cannot allocate format context";
  201. return false;
  202. }
  203. AVInputFormat* fmt = nullptr;
  204. int result = 0;
  205. if (in) {
  206. ImageType type = ImageType::UNKNOWN;
  207. if ((result = seekableBuffer_.init(
  208. std::forward<DecoderInCallback>(in),
  209. params_.timeoutMs,
  210. params_.maxSeekableBytes,
  211. params_.isImage ? &type : nullptr)) < 0) {
  212. LOG(ERROR) << "uuid=" << params_.loggingUuid
  213. << " can't initiate seekable buffer";
  214. cleanUp();
  215. return false;
  216. }
  217. if (params_.isImage) {
  218. const char* fmtName = "image2";
  219. switch (type) {
  220. case ImageType::JPEG:
  221. fmtName = "jpeg_pipe";
  222. break;
  223. case ImageType::PNG:
  224. fmtName = "png_pipe";
  225. break;
  226. case ImageType::TIFF:
  227. fmtName = "tiff_pipe";
  228. break;
  229. default:
  230. break;
  231. }
  232. fmt = (AVInputFormat*)av_find_input_format(fmtName);
  233. }
  234. const size_t avioCtxBufferSize = kIoBufferSize;
  235. uint8_t* avioCtxBuffer =
  236. (uint8_t*)av_malloc(avioCtxBufferSize + kIoPaddingSize);
  237. if (!avioCtxBuffer) {
  238. LOG(ERROR) << "uuid=" << params_.loggingUuid
  239. << " av_malloc cannot allocate " << avioCtxBufferSize
  240. << " bytes";
  241. cleanUp();
  242. return false;
  243. }
  244. if (!(avioCtx_ = avio_alloc_context(
  245. avioCtxBuffer,
  246. avioCtxBufferSize,
  247. 0,
  248. reinterpret_cast<void*>(this),
  249. &Decoder::readFunction,
  250. nullptr,
  251. result == 1 ? &Decoder::seekFunction : nullptr))) {
  252. LOG(ERROR) << "uuid=" << params_.loggingUuid
  253. << " avio_alloc_context failed";
  254. av_free(avioCtxBuffer);
  255. cleanUp();
  256. return false;
  257. }
  258. inputCtx_->pb = avioCtx_;
  259. inputCtx_->flags |= AVFMT_FLAG_CUSTOM_IO;
  260. }
  261. inputCtx_->opaque = reinterpret_cast<void*>(this);
  262. inputCtx_->interrupt_callback.callback = Decoder::shutdownFunction;
  263. inputCtx_->interrupt_callback.opaque = reinterpret_cast<void*>(this);
  264. // add network timeout
  265. inputCtx_->flags |= AVFMT_FLAG_NONBLOCK;
  266. AVDictionary* options = nullptr;
  267. if (params_.listen) {
  268. av_dict_set_int(&options, "listen", 1, 0);
  269. }
  270. if (params_.timeoutMs > 0) {
  271. av_dict_set_int(&options, "analyzeduration", params_.timeoutMs * 1000, 0);
  272. av_dict_set_int(&options, "stimeout", params_.timeoutMs * 1000, 0);
  273. av_dict_set_int(&options, "rw_timeout", params_.timeoutMs * 1000, 0);
  274. if (!params_.tlsCertFile.empty()) {
  275. av_dict_set(&options, "cert_file", params_.tlsCertFile.data(), 0);
  276. }
  277. if (!params_.tlsKeyFile.empty()) {
  278. av_dict_set(&options, "key_file", params_.tlsKeyFile.data(), 0);
  279. }
  280. }
  281. av_dict_set_int(&options, "probesize", params_.probeSize, 0);
  282. interrupted_ = false;
  283. // ffmpeg avformat_open_input call can hang if media source doesn't respond
  284. // set a guard for handle such situations, if requested
  285. std::promise<bool> p;
  286. std::future<bool> f = p.get_future();
  287. std::unique_ptr<std::thread> guard;
  288. if (params_.preventStaleness) {
  289. guard = std::make_unique<std::thread>([&f, this]() {
  290. auto timeout = std::chrono::milliseconds(params_.timeoutMs);
  291. if (std::future_status::timeout == f.wait_for(timeout)) {
  292. LOG(ERROR) << "uuid=" << params_.loggingUuid
  293. << " cannot open stream within " << params_.timeoutMs
  294. << " ms";
  295. interrupted_ = true;
  296. }
  297. });
  298. }
  299. if (fmt) {
  300. result = avformat_open_input(&inputCtx_, nullptr, fmt, &options);
  301. } else {
  302. result =
  303. avformat_open_input(&inputCtx_, params_.uri.c_str(), nullptr, &options);
  304. }
  305. av_dict_free(&options);
  306. if (guard) {
  307. p.set_value(true);
  308. guard->join();
  309. guard.reset();
  310. }
  311. if (result < 0 || interrupted_) {
  312. LOG(ERROR) << "uuid=" << params_.loggingUuid
  313. << " avformat_open_input failed, error="
  314. << Util::generateErrorDesc(result);
  315. cleanUp();
  316. return false;
  317. }
  318. result = avformat_find_stream_info(inputCtx_, nullptr);
  319. if (result < 0) {
  320. LOG(ERROR) << "uuid=" << params_.loggingUuid
  321. << " avformat_find_stream_info failed, error="
  322. << Util::generateErrorDesc(result);
  323. cleanUp();
  324. return false;
  325. }
  326. if (!openStreams(metadata)) {
  327. LOG(ERROR) << "uuid=" << params_.loggingUuid << " cannot activate streams";
  328. cleanUp();
  329. return false;
  330. }
  331. // SyncDecoder inherits Decoder which would override onInit.
  332. onInit();
  333. if (params.startOffset != 0) {
  334. auto offset = params.startOffset <= params.seekAccuracy
  335. ? 0
  336. : params.startOffset - params.seekAccuracy;
  337. av_seek_frame(inputCtx_, -1, offset, AVSEEK_FLAG_BACKWARD);
  338. }
  339. VLOG(1) << "Decoder initialized, log level: " << params_.logLevel;
  340. return true;
  341. }
  342. // open appropriate CODEC for every type of stream and move it to the class
  343. // variable `streams_` and make sure it is in range for decoding
  344. bool Decoder::openStreams(std::vector<DecoderMetadata>* metadata) {
  345. for (unsigned int i = 0; i < inputCtx_->nb_streams; i++) {
  346. // - find the corespondent format at params_.formats set
  347. MediaFormat format;
  348. #if LIBAVUTIL_VERSION_MAJOR < 56 // Before FFMPEG 4.0
  349. const auto media = inputCtx_->streams[i]->codec->codec_type;
  350. #else // FFMPEG 4.0+
  351. const auto media = inputCtx_->streams[i]->codecpar->codec_type;
  352. #endif
  353. if (!mapFfmpegType(media, &format.type)) {
  354. VLOG(1) << "Stream media: " << media << " at index " << i
  355. << " gets ignored, unknown type";
  356. continue; // unsupported type
  357. }
  358. // check format
  359. auto it = params_.formats.find(format);
  360. if (it == params_.formats.end()) {
  361. VLOG(1) << "Stream type: " << format.type << " at index: " << i
  362. << " gets ignored, caller is not interested";
  363. continue; // clients don't care about this media format
  364. }
  365. // do we have stream of this type?
  366. auto stream = findByType(format);
  367. // should we process this stream?
  368. if (it->stream == -2 || // all streams of this type are welcome
  369. (!stream && (it->stream == -1 || it->stream == i))) { // new stream
  370. VLOG(1) << "Stream type: " << format.type << " found, at index: " << i;
  371. auto stream = createStream(
  372. format.type,
  373. inputCtx_,
  374. i,
  375. params_.convertPtsToWallTime,
  376. it->format,
  377. params_.loggingUuid);
  378. CHECK(stream);
  379. if (stream->openCodec(metadata, params_.numThreads) < 0) {
  380. LOG(ERROR) << "uuid=" << params_.loggingUuid
  381. << " open codec failed, stream_idx=" << i;
  382. return false;
  383. }
  384. streams_.emplace(i, std::move(stream));
  385. inRange_.set(i, true);
  386. }
  387. }
  388. return true;
  389. }
  390. void Decoder::shutdown() {
  391. cleanUp();
  392. }
  393. void Decoder::interrupt() {
  394. interrupted_ = true;
  395. }
  396. void Decoder::cleanUp() {
  397. if (!interrupted_) {
  398. interrupted_ = true;
  399. }
  400. if (inputCtx_) {
  401. for (auto& stream : streams_) {
  402. // Drain stream buffers.
  403. DecoderOutputMessage msg;
  404. while (msg.payload = nullptr, stream.second->flush(&msg, true) > 0) {
  405. }
  406. stream.second.reset();
  407. }
  408. streams_.clear();
  409. avformat_close_input(&inputCtx_);
  410. }
  411. if (avioCtx_) {
  412. av_freep(&avioCtx_->buffer);
  413. av_freep(&avioCtx_);
  414. }
  415. // reset callback
  416. seekableBuffer_.shutdown();
  417. }
  418. // function does actual work, derived class calls it in working thread
  419. // periodically. On success method returns 0, ENODATA on EOF, ETIMEDOUT if
  420. // no frames got decoded in the specified timeout time, AVERROR_BUFFER_TOO_SMALL
  421. // when unable to allocate packet and error on unrecoverable error
  422. int Decoder::getFrame(size_t workingTimeInMs) {
  423. if (inRange_.none()) {
  424. return ENODATA;
  425. }
  426. // decode frames until cache is full and leave thread
  427. // once decode() method gets called and grab some bytes
  428. // run this method again
  429. // init package
  430. // update 03/22: moving memory management to ffmpeg
  431. AVPacket* avPacket;
  432. avPacket = av_packet_alloc();
  433. if (avPacket == nullptr) {
  434. LOG(ERROR) << "uuid=" << params_.loggingUuid
  435. << " decoder as not able to allocate the packet.";
  436. return AVERROR_BUFFER_TOO_SMALL;
  437. }
  438. avPacket->data = nullptr;
  439. avPacket->size = 0;
  440. auto end = std::chrono::steady_clock::now() +
  441. std::chrono::milliseconds(workingTimeInMs);
  442. // return true if elapsed time less than timeout
  443. auto watcher = [end]() -> bool {
  444. return std::chrono::steady_clock::now() <= end;
  445. };
  446. int result = 0;
  447. size_t decodingErrors = 0;
  448. bool decodedFrame = false;
  449. while (!interrupted_ && inRange_.any() && !decodedFrame) {
  450. if (watcher() == false) {
  451. LOG(ERROR) << "uuid=" << params_.loggingUuid << " hit ETIMEDOUT";
  452. result = ETIMEDOUT;
  453. break;
  454. }
  455. result = av_read_frame(inputCtx_, avPacket);
  456. if (result == AVERROR(EAGAIN)) {
  457. VLOG(4) << "Decoder is busy...";
  458. std::this_thread::yield();
  459. result = 0; // reset error, EAGAIN is not an error at all
  460. // reset the packet to default settings
  461. av_packet_unref(avPacket);
  462. continue;
  463. } else if (result == AVERROR_EOF) {
  464. flushStreams();
  465. VLOG(1) << "End of stream";
  466. result = ENODATA;
  467. break;
  468. } else if (
  469. result == AVERROR(EPERM) && params_.skipOperationNotPermittedPackets) {
  470. // reset error, lets skip packets with EPERM
  471. result = 0;
  472. // reset the packet to default settings
  473. av_packet_unref(avPacket);
  474. continue;
  475. } else if (result < 0) {
  476. flushStreams();
  477. LOG(ERROR) << "uuid=" << params_.loggingUuid
  478. << " error detected: " << Util::generateErrorDesc(result);
  479. break;
  480. }
  481. // get stream; if stream cannot be found reset the packet to
  482. // default settings
  483. auto stream = findByIndex(avPacket->stream_index);
  484. if (stream == nullptr || !inRange_.test(stream->getIndex())) {
  485. av_packet_unref(avPacket);
  486. continue;
  487. }
  488. size_t numConsecutiveNoBytes = 0;
  489. // it can be only partial decoding of the package bytes
  490. do {
  491. // decode package
  492. bool gotFrame = false;
  493. bool hasMsg = false;
  494. // packet either got consumed completely or not at all
  495. if ((result = processPacket(
  496. stream, avPacket, &gotFrame, &hasMsg, params_.fastSeek)) < 0) {
  497. LOG(ERROR) << "uuid=" << params_.loggingUuid
  498. << " processPacket failed with code: " << result;
  499. break;
  500. }
  501. if (!gotFrame && params_.maxProcessNoBytes != 0 &&
  502. ++numConsecutiveNoBytes > params_.maxProcessNoBytes) {
  503. LOG(ERROR) << "uuid=" << params_.loggingUuid
  504. << " exceeding max amount of consecutive no bytes";
  505. break;
  506. }
  507. if (result > 0) {
  508. numConsecutiveNoBytes = 0;
  509. }
  510. decodedFrame |= hasMsg;
  511. } while (result == 0);
  512. // post loop check
  513. if (result < 0) {
  514. if (params_.maxPackageErrors != 0 && // check errors
  515. ++decodingErrors >= params_.maxPackageErrors) { // reached the limit
  516. LOG(ERROR) << "uuid=" << params_.loggingUuid
  517. << " exceeding max amount of consecutive package errors";
  518. break;
  519. }
  520. } else {
  521. decodingErrors = 0; // reset on success
  522. }
  523. result = 0;
  524. av_packet_unref(avPacket);
  525. }
  526. av_packet_free(&avPacket);
  527. VLOG(2) << "Interrupted loop"
  528. << ", interrupted_ " << interrupted_ << ", inRange_.any() "
  529. << inRange_.any() << ", decodedFrame " << decodedFrame << ", result "
  530. << result;
  531. // loop can be terminated, either by:
  532. // 1. explicitly interrupted
  533. // 3. unrecoverable error or ENODATA (end of stream) or ETIMEDOUT (timeout)
  534. // 4. decoded frames pts are out of the specified range
  535. // 5. success decoded frame
  536. if (interrupted_) {
  537. return EINTR;
  538. }
  539. if (result != 0) {
  540. return result;
  541. }
  542. if (inRange_.none()) {
  543. return ENODATA;
  544. }
  545. return 0;
  546. }
  547. // find stream by stream index
  548. Stream* Decoder::findByIndex(int streamIndex) const {
  549. auto it = streams_.find(streamIndex);
  550. return it != streams_.end() ? it->second.get() : nullptr;
  551. }
  552. // find stream by type; note finds only the first stream of a given type
  553. Stream* Decoder::findByType(const MediaFormat& format) const {
  554. for (auto& stream : streams_) {
  555. if (stream.second->getMediaFormat().type == format.type) {
  556. return stream.second.get();
  557. }
  558. }
  559. return nullptr;
  560. }
  561. // given the stream and packet, decode the frame buffers into the
  562. // DecoderOutputMessage data structure via stream::decodePacket function.
  563. int Decoder::processPacket(
  564. Stream* stream,
  565. AVPacket* packet,
  566. bool* gotFrame,
  567. bool* hasMsg,
  568. bool fastSeek) {
  569. // decode package
  570. int result;
  571. DecoderOutputMessage msg;
  572. msg.payload = params_.headerOnly ? nullptr : createByteStorage(0);
  573. *hasMsg = false;
  574. if ((result = stream->decodePacket(
  575. packet, &msg, params_.headerOnly, gotFrame)) >= 0 &&
  576. *gotFrame) {
  577. // check end offset
  578. bool endInRange =
  579. params_.endOffset <= 0 || msg.header.pts <= params_.endOffset;
  580. inRange_.set(stream->getIndex(), endInRange);
  581. // if fastseek is enabled, we're returning the first
  582. // frame that we decode after (potential) seek.
  583. // By default, we perform accurate seek to the closest
  584. // following frame
  585. bool startCondition = true;
  586. if (!fastSeek) {
  587. startCondition = msg.header.pts >= params_.startOffset;
  588. }
  589. if (endInRange && startCondition) {
  590. *hasMsg = true;
  591. push(std::move(msg));
  592. }
  593. }
  594. return result;
  595. }
  596. void Decoder::flushStreams() {
  597. VLOG(1) << "Flushing streams...";
  598. for (auto& stream : streams_) {
  599. DecoderOutputMessage msg;
  600. while (msg.payload = (params_.headerOnly ? nullptr : createByteStorage(0)),
  601. stream.second->flush(&msg, params_.headerOnly) > 0) {
  602. // check end offset
  603. bool endInRange =
  604. params_.endOffset <= 0 || msg.header.pts <= params_.endOffset;
  605. inRange_.set(stream.second->getIndex(), endInRange);
  606. if (endInRange && msg.header.pts >= params_.startOffset) {
  607. push(std::move(msg));
  608. } else {
  609. msg.payload.reset();
  610. }
  611. }
  612. }
  613. }
  614. int Decoder::decode_all(const DecoderOutCallback& callback) {
  615. int result;
  616. do {
  617. DecoderOutputMessage out;
  618. if (0 == (result = decode(&out, params_.timeoutMs))) {
  619. callback(std::move(out));
  620. }
  621. } while (result == 0);
  622. return result;
  623. }
  624. } // namespace ffmpeg