ffmpeg_bytes_io_wrap.h 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. /*
  2. This file is part of Telegram Desktop,
  3. the official desktop application for the Telegram messaging service.
  4. For license and copyright information please follow this link:
  5. https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
  6. */
  7. #pragma once
  8. #include "ffmpeg/ffmpeg_utility.h"
  9. namespace FFmpeg {
  10. struct ReadBytesWrap {
  11. int64 size = 0;
  12. int64 offset = 0;
  13. const uchar *data = nullptr;
  14. static int Read(void *opaque, uint8_t *buf, int buf_size) {
  15. auto wrap = static_cast<ReadBytesWrap*>(opaque);
  16. const auto toRead = std::min(
  17. int64(buf_size),
  18. wrap->size - wrap->offset);
  19. if (!toRead) {
  20. return AVERROR_EOF;
  21. } else if (toRead > 0) {
  22. memcpy(buf, wrap->data + wrap->offset, toRead);
  23. wrap->offset += toRead;
  24. }
  25. return toRead;
  26. }
  27. static int64_t Seek(void *opaque, int64_t offset, int whence) {
  28. auto wrap = static_cast<ReadBytesWrap*>(opaque);
  29. auto updated = int64(-1);
  30. switch (whence) {
  31. case SEEK_SET: updated = offset; break;
  32. case SEEK_CUR: updated = wrap->offset + offset; break;
  33. case SEEK_END: updated = wrap->size + offset; break;
  34. case AVSEEK_SIZE: return wrap->size; break;
  35. }
  36. if (updated < 0 || updated > wrap->size) {
  37. return -1;
  38. }
  39. wrap->offset = updated;
  40. return updated;
  41. }
  42. };
  43. struct WriteBytesWrap {
  44. QByteArray content;
  45. int64 offset = 0;
  46. #if DA_FFMPEG_CONST_WRITE_CALLBACK
  47. static int Write(void *opaque, const uint8_t *_buf, int buf_size) {
  48. uint8_t *buf = const_cast<uint8_t *>(_buf);
  49. #else
  50. static int Write(void *opaque, uint8_t *buf, int buf_size) {
  51. #endif
  52. auto wrap = static_cast<WriteBytesWrap*>(opaque);
  53. if (const auto total = wrap->offset + int64(buf_size)) {
  54. const auto size = int64(wrap->content.size());
  55. constexpr auto kReserve = 1024 * 1024;
  56. wrap->content.reserve((total / kReserve) * kReserve);
  57. const auto overwrite = std::min(
  58. size - wrap->offset,
  59. int64(buf_size));
  60. if (overwrite) {
  61. memcpy(wrap->content.data() + wrap->offset, buf, overwrite);
  62. }
  63. if (const auto append = buf_size - overwrite) {
  64. wrap->content.append(
  65. reinterpret_cast<const char*>(buf) + overwrite,
  66. append);
  67. }
  68. wrap->offset += buf_size;
  69. }
  70. return buf_size;
  71. }
  72. static int64_t Seek(void *opaque, int64_t offset, int whence) {
  73. auto wrap = static_cast<WriteBytesWrap*>(opaque);
  74. const auto &content = wrap->content;
  75. const auto checkedSeek = [&](int64_t offset) {
  76. if (offset < 0 || offset > int64(content.size())) {
  77. return int64_t(-1);
  78. }
  79. return int64_t(wrap->offset = offset);
  80. };
  81. switch (whence) {
  82. case SEEK_SET: return checkedSeek(offset);
  83. case SEEK_CUR: return checkedSeek(wrap->offset + offset);
  84. case SEEK_END: return checkedSeek(int64(content.size()) + offset);
  85. case AVSEEK_SIZE: return int64(content.size());
  86. }
  87. return -1;
  88. }
  89. };
  90. } // namespace FFmpeg