demuxer.h 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. extern "C" {
  2. #include <libavcodec/avcodec.h>
  3. #include <libavcodec/bsf.h>
  4. #include <libavformat/avformat.h>
  5. #include <libavformat/avio.h>
  6. }
  7. class Demuxer {
  8. private:
  9. AVFormatContext* fmtCtx = NULL;
  10. AVBSFContext* bsfCtx = NULL;
  11. AVPacket pkt, pktFiltered;
  12. AVCodecID eVideoCodec;
  13. uint8_t* dataWithHeader = NULL;
  14. bool bMp4H264, bMp4HEVC, bMp4MPEG4;
  15. unsigned int frameCount = 0;
  16. int iVideoStream;
  17. double timeBase = 0.0;
  18. public:
  19. Demuxer(const char* filePath) {
  20. avformat_network_init();
  21. TORCH_CHECK(
  22. 0 <= avformat_open_input(&fmtCtx, filePath, NULL, NULL),
  23. "avformat_open_input() failed at line ",
  24. __LINE__,
  25. " in demuxer.h\n");
  26. if (!fmtCtx) {
  27. TORCH_CHECK(
  28. false,
  29. "Encountered NULL AVFormatContext at line ",
  30. __LINE__,
  31. " in demuxer.h\n");
  32. }
  33. TORCH_CHECK(
  34. 0 <= avformat_find_stream_info(fmtCtx, NULL),
  35. "avformat_find_stream_info() failed at line ",
  36. __LINE__,
  37. " in demuxer.h\n");
  38. iVideoStream =
  39. av_find_best_stream(fmtCtx, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0);
  40. if (iVideoStream < 0) {
  41. TORCH_CHECK(
  42. false,
  43. "av_find_best_stream() failed at line ",
  44. __LINE__,
  45. " in demuxer.h\n");
  46. }
  47. eVideoCodec = fmtCtx->streams[iVideoStream]->codecpar->codec_id;
  48. AVRational rTimeBase = fmtCtx->streams[iVideoStream]->time_base;
  49. timeBase = av_q2d(rTimeBase);
  50. bMp4H264 = eVideoCodec == AV_CODEC_ID_H264 &&
  51. (!strcmp(fmtCtx->iformat->long_name, "QuickTime / MOV") ||
  52. !strcmp(fmtCtx->iformat->long_name, "FLV (Flash Video)") ||
  53. !strcmp(fmtCtx->iformat->long_name, "Matroska / WebM"));
  54. bMp4HEVC = eVideoCodec == AV_CODEC_ID_HEVC &&
  55. (!strcmp(fmtCtx->iformat->long_name, "QuickTime / MOV") ||
  56. !strcmp(fmtCtx->iformat->long_name, "FLV (Flash Video)") ||
  57. !strcmp(fmtCtx->iformat->long_name, "Matroska / WebM"));
  58. bMp4MPEG4 = eVideoCodec == AV_CODEC_ID_MPEG4 &&
  59. (!strcmp(fmtCtx->iformat->long_name, "QuickTime / MOV") ||
  60. !strcmp(fmtCtx->iformat->long_name, "FLV (Flash Video)") ||
  61. !strcmp(fmtCtx->iformat->long_name, "Matroska / WebM"));
  62. av_init_packet(&pkt);
  63. pkt.data = NULL;
  64. pkt.size = 0;
  65. av_init_packet(&pktFiltered);
  66. pktFiltered.data = NULL;
  67. pktFiltered.size = 0;
  68. if (bMp4H264) {
  69. const AVBitStreamFilter* bsf = av_bsf_get_by_name("h264_mp4toannexb");
  70. if (!bsf) {
  71. TORCH_CHECK(
  72. false,
  73. "av_bsf_get_by_name() failed at line ",
  74. __LINE__,
  75. " in demuxer.h\n");
  76. }
  77. TORCH_CHECK(
  78. 0 <= av_bsf_alloc(bsf, &bsfCtx),
  79. "av_bsf_alloc() failed at line ",
  80. __LINE__,
  81. " in demuxer.h\n");
  82. avcodec_parameters_copy(
  83. bsfCtx->par_in, fmtCtx->streams[iVideoStream]->codecpar);
  84. TORCH_CHECK(
  85. 0 <= av_bsf_init(bsfCtx),
  86. "av_bsf_init() failed at line ",
  87. __LINE__,
  88. " in demuxer.h\n");
  89. }
  90. if (bMp4HEVC) {
  91. const AVBitStreamFilter* bsf = av_bsf_get_by_name("hevc_mp4toannexb");
  92. if (!bsf) {
  93. TORCH_CHECK(
  94. false,
  95. "av_bsf_get_by_name() failed at line ",
  96. __LINE__,
  97. " in demuxer.h\n");
  98. }
  99. TORCH_CHECK(
  100. 0 <= av_bsf_alloc(bsf, &bsfCtx),
  101. "av_bsf_alloc() failed at line ",
  102. __LINE__,
  103. " in demuxer.h\n");
  104. avcodec_parameters_copy(
  105. bsfCtx->par_in, fmtCtx->streams[iVideoStream]->codecpar);
  106. TORCH_CHECK(
  107. 0 <= av_bsf_init(bsfCtx),
  108. "av_bsf_init() failed at line ",
  109. __LINE__,
  110. " in demuxer.h\n");
  111. }
  112. }
  113. ~Demuxer() {
  114. if (!fmtCtx) {
  115. return;
  116. }
  117. if (pkt.data) {
  118. av_packet_unref(&pkt);
  119. }
  120. if (pktFiltered.data) {
  121. av_packet_unref(&pktFiltered);
  122. }
  123. if (bsfCtx) {
  124. av_bsf_free(&bsfCtx);
  125. }
  126. avformat_close_input(&fmtCtx);
  127. if (dataWithHeader) {
  128. av_free(dataWithHeader);
  129. }
  130. }
  131. AVCodecID get_video_codec() {
  132. return eVideoCodec;
  133. }
  134. double get_duration() const {
  135. return (double)fmtCtx->duration / AV_TIME_BASE;
  136. }
  137. double get_fps() const {
  138. return av_q2d(fmtCtx->streams[iVideoStream]->r_frame_rate);
  139. }
  140. bool demux(uint8_t** video, unsigned long* videoBytes) {
  141. if (!fmtCtx) {
  142. return false;
  143. }
  144. *videoBytes = 0;
  145. if (pkt.data) {
  146. av_packet_unref(&pkt);
  147. }
  148. int e = 0;
  149. while ((e = av_read_frame(fmtCtx, &pkt)) >= 0 &&
  150. pkt.stream_index != iVideoStream) {
  151. av_packet_unref(&pkt);
  152. }
  153. if (e < 0) {
  154. return false;
  155. }
  156. if (bMp4H264 || bMp4HEVC) {
  157. if (pktFiltered.data) {
  158. av_packet_unref(&pktFiltered);
  159. }
  160. TORCH_CHECK(
  161. 0 <= av_bsf_send_packet(bsfCtx, &pkt),
  162. "av_bsf_send_packet() failed at line ",
  163. __LINE__,
  164. " in demuxer.h\n");
  165. TORCH_CHECK(
  166. 0 <= av_bsf_receive_packet(bsfCtx, &pktFiltered),
  167. "av_bsf_receive_packet() failed at line ",
  168. __LINE__,
  169. " in demuxer.h\n");
  170. *video = pktFiltered.data;
  171. *videoBytes = pktFiltered.size;
  172. } else {
  173. if (bMp4MPEG4 && (frameCount == 0)) {
  174. int extraDataSize =
  175. fmtCtx->streams[iVideoStream]->codecpar->extradata_size;
  176. if (extraDataSize > 0) {
  177. dataWithHeader = (uint8_t*)av_malloc(
  178. extraDataSize + pkt.size - 3 * sizeof(uint8_t));
  179. if (!dataWithHeader) {
  180. TORCH_CHECK(
  181. false,
  182. "av_malloc() failed at line ",
  183. __LINE__,
  184. " in demuxer.h\n");
  185. }
  186. memcpy(
  187. dataWithHeader,
  188. fmtCtx->streams[iVideoStream]->codecpar->extradata,
  189. extraDataSize);
  190. memcpy(
  191. dataWithHeader + extraDataSize,
  192. pkt.data + 3,
  193. pkt.size - 3 * sizeof(uint8_t));
  194. *video = dataWithHeader;
  195. *videoBytes = extraDataSize + pkt.size - 3 * sizeof(uint8_t);
  196. }
  197. } else {
  198. *video = pkt.data;
  199. *videoBytes = pkt.size;
  200. }
  201. }
  202. frameCount++;
  203. return true;
  204. }
  205. void seek(double timestamp, int flag) {
  206. int64_t time = timestamp * AV_TIME_BASE;
  207. TORCH_CHECK(
  208. 0 <= av_seek_frame(fmtCtx, -1, time, flag),
  209. "av_seek_frame() failed at line ",
  210. __LINE__,
  211. " in demuxer.h\n");
  212. }
  213. };
  214. inline cudaVideoCodec ffmpeg_to_codec(AVCodecID id) {
  215. switch (id) {
  216. case AV_CODEC_ID_MPEG1VIDEO:
  217. return cudaVideoCodec_MPEG1;
  218. case AV_CODEC_ID_MPEG2VIDEO:
  219. return cudaVideoCodec_MPEG2;
  220. case AV_CODEC_ID_MPEG4:
  221. return cudaVideoCodec_MPEG4;
  222. case AV_CODEC_ID_WMV3:
  223. case AV_CODEC_ID_VC1:
  224. return cudaVideoCodec_VC1;
  225. case AV_CODEC_ID_H264:
  226. return cudaVideoCodec_H264;
  227. case AV_CODEC_ID_HEVC:
  228. return cudaVideoCodec_HEVC;
  229. case AV_CODEC_ID_VP8:
  230. return cudaVideoCodec_VP8;
  231. case AV_CODEC_ID_VP9:
  232. return cudaVideoCodec_VP9;
  233. case AV_CODEC_ID_MJPEG:
  234. return cudaVideoCodec_JPEG;
  235. case AV_CODEC_ID_AV1:
  236. return cudaVideoCodec_AV1;
  237. default:
  238. return cudaVideoCodec_NumCodecs;
  239. }
  240. }