PageRenderTime 51ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/src/fileaccess/fa_libav.c

https://github.com/bielorkut/showtime
C | 237 lines | 147 code | 40 blank | 50 comment | 36 complexity | 49f6545cb11f714ece6a6b7ab66f82cb MD5 | raw file
  1. /*
  2. * File access <-> AVIOContext
  3. * Copyright (C) 2011 Andreas Ă–man
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation, either version 3 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. #include "showtime.h"
  19. #include "fa_libav.h"
  20. /**
  21. *
  22. */
  23. static int
  24. fa_libav_read(void *opaque, uint8_t *buf, int size)
  25. {
  26. fa_handle_t *fh = opaque;
  27. return fa_read(fh, buf, size);
  28. }
  29. /**
  30. *
  31. */
  32. static int64_t
  33. fa_libav_seek(void *opaque, int64_t offset, int whence)
  34. {
  35. fa_handle_t *fh = opaque;
  36. if(whence == AVSEEK_SIZE)
  37. return fa_fsize(fh);
  38. return fa_seek(fh, offset, whence & ~AVSEEK_FORCE);
  39. }
  40. /**
  41. *
  42. */
  43. AVIOContext *
  44. fa_libav_reopen(fa_handle_t *fh, int buf_size)
  45. {
  46. AVIOContext *avio;
  47. if(buf_size == 0)
  48. buf_size = 32768;
  49. void *buf = malloc(buf_size);
  50. avio = avio_alloc_context(buf, buf_size, 0, fh, fa_libav_read, NULL,
  51. fa_libav_seek);
  52. if(fa_fsize(fh) == -1)
  53. avio->seekable = 0;
  54. return avio;
  55. }
  56. /**
  57. *
  58. */
  59. AVIOContext *
  60. fa_libav_open(const char *url, int buf_size, char *errbuf, size_t errlen,
  61. int flags, struct prop *stats)
  62. {
  63. fa_handle_t *fh;
  64. if((fh = fa_open_ex(url, errbuf, errlen, flags, stats)) == NULL)
  65. return NULL;
  66. return fa_libav_reopen(fh, buf_size);
  67. }
  68. /**
  69. *
  70. */
  71. AVIOContext *
  72. fa_libav_open_vpaths(const char *url, int buf_size, const char **vpaths)
  73. {
  74. fa_handle_t *fh;
  75. if((fh = fa_open_vpaths(url, vpaths)) == NULL)
  76. return NULL;
  77. return fa_libav_reopen(fh, buf_size);
  78. }
  79. /**
  80. *
  81. */
  82. static AVFormatContext *
  83. fa_libav_open_error(char *errbuf, size_t errlen, const char *hdr, int errcode)
  84. {
  85. char libaverr[256];
  86. if(av_strerror(errcode, libaverr, sizeof(libaverr)))
  87. snprintf(libaverr, sizeof(libaverr), "libav error %d", errcode);
  88. snprintf(errbuf, errlen, "%s: %s", hdr, libaverr);
  89. return NULL;
  90. }
  91. /**
  92. *
  93. */
  94. static const struct {
  95. const char *mimetype;
  96. const char *fmt;
  97. } mimetype2fmt[] = {
  98. { "video/x-matroska", "matroska" },
  99. { "video/quicktime", "mov" },
  100. { "video/mp4", "mp4" },
  101. { "video/x-msvideo", "avi" },
  102. { "video/vnd.dlna.mpeg-tts,", "mpegts" },
  103. { "video/avi", "avi" },
  104. { "audio/x-mpeg", "mp3" },
  105. };
  106. /**
  107. *
  108. */
  109. AVFormatContext *
  110. fa_libav_open_format(AVIOContext *avio, const char *url,
  111. char *errbuf, size_t errlen, const char *mimetype)
  112. {
  113. AVInputFormat *fmt = NULL;
  114. AVFormatContext *fctx;
  115. int err;
  116. avio_seek(avio, 0, SEEK_SET);
  117. if(mimetype != NULL) {
  118. int i;
  119. for(i = 0; i < sizeof(mimetype2fmt) / sizeof(mimetype2fmt[0]); i++) {
  120. if(!strcmp(mimetype, mimetype2fmt[i].mimetype)) {
  121. fmt = av_find_input_format(mimetype2fmt[i].fmt);
  122. break;
  123. }
  124. }
  125. if(fmt == NULL)
  126. TRACE(TRACE_DEBUG, "probe", "Don't know mimetype %s, probing instead",
  127. mimetype);
  128. }
  129. if(fmt == NULL) {
  130. if((err = av_probe_input_buffer(avio, &fmt, url, NULL, 0, 0)) != 0)
  131. return fa_libav_open_error(errbuf, errlen,
  132. "Unable to probe file", err);
  133. if(fmt == NULL) {
  134. snprintf(errbuf, errlen, "Unknown file format");
  135. return NULL;
  136. }
  137. }
  138. fctx = avformat_alloc_context();
  139. fctx->pb = avio;
  140. if((err = avformat_open_input(&fctx, url, fmt, NULL)) != 0) {
  141. if(mimetype != NULL)
  142. return fa_libav_open_format(avio, url, errbuf, errlen, NULL);
  143. return fa_libav_open_error(errbuf, errlen,
  144. "Unable to open file as input format", err);
  145. }
  146. if(av_find_stream_info(fctx) < 0) {
  147. av_close_input_stream(fctx);
  148. if(mimetype != NULL)
  149. return fa_libav_open_format(avio, url, errbuf, errlen, NULL);
  150. return fa_libav_open_error(errbuf, errlen,
  151. "Unable to handle file contents", err);
  152. }
  153. return fctx;
  154. }
  155. /**
  156. *
  157. */
  158. void
  159. fa_libav_close(AVIOContext *avio)
  160. {
  161. fa_close(avio->opaque);
  162. free(avio->buffer);
  163. av_free(avio);
  164. }
  165. /**
  166. *
  167. */
  168. void
  169. fa_libav_close_format(AVFormatContext *fctx)
  170. {
  171. AVIOContext *avio = fctx->pb;
  172. av_close_input_stream(fctx);
  173. fa_libav_close(avio);
  174. }
  175. /**
  176. *
  177. */
  178. uint8_t *
  179. fa_libav_load_and_close(AVIOContext *avio, size_t *sizep)
  180. {
  181. size_t r;
  182. size_t size = avio_size(avio);
  183. if(size == -1)
  184. return NULL;
  185. uint8_t *mem = malloc(size+1);
  186. avio_seek(avio, 0, SEEK_SET);
  187. r = avio_read(avio, mem, size);
  188. fa_libav_close(avio);
  189. if(r != size) {
  190. free(mem);
  191. return NULL;
  192. }
  193. if(sizep != NULL)
  194. *sizep = size;
  195. mem[size] = 0;
  196. return mem;
  197. }