Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  1. /*
  2. * libpipi Pathetic image processing interface library
  3. * Copyright (c) 2004-2009 Sam Hocevar <sam@hocevar.net>
  4. * All Rights Reserved
  5. *
  6. * $Id$
  7. *
  8. * This library is free software. It comes without any warranty, to
  9. * the extent permitted by applicable law. You can redistribute it
  10. * and/or modify it under the terms of the Do What The Fuck You Want
  11. * To Public License, Version 2, as published by Sam Hocevar. See
  12. * http://sam.zoy.org/wtfpl/COPYING for more details.
  13. */
  14. /*
  15. * codec.c: image I/O functions
  16. */
  17. #include "config.h"
  18. #if defined _WIN32
  19. # undef _CRT_SECURE_NO_WARNINGS
  20. # define _CRT_SECURE_NO_WARNINGS /* I know how to use snprintf, thank you */
  21. # define snprintf _snprintf
  22. #endif
  23. #include <stdio.h>
  24. #include <stdlib.h>
  25. #include <string.h>
  26. #if defined USE_FFMPEG
  27. # include <libavformat/avformat.h>
  28. # include <libswscale/swscale.h>
  29. #endif
  30. #include "pipi.h"
  31. #include "pipi_internals.h"
  32. #if defined USE_FFMPEG
  33. typedef struct
  34. {
  35. uint8_t *buf;
  36. size_t buf_len;
  37. AVFormatContext *fmt_ctx;
  38. AVStream *stream;
  39. AVCodecContext *cod_ctx;
  40. AVCodec *codec;
  41. AVFrame *frame;
  42. struct SwsContext *sws_ctx;
  43. int src_width, src_height;
  44. }
  45. ffmpeg_codec_t;
  46. #endif
  47. #define PAR_NUM 1
  48. #define PAR_DEN 1
  49. #define BITRATE (16 * 1024 * 1024)
  50. pipi_sequence_t *pipi_open_sequence(char *file, int width, int height, int fps)
  51. {
  52. #if defined USE_FFMPEG
  53. static int initialised = 0;
  54. pipi_sequence_t *seq;
  55. ffmpeg_codec_t *ff;
  56. uint8_t *tmp;
  57. seq = malloc(sizeof(pipi_sequence_t));
  58. seq->w = width;
  59. seq->h = height;
  60. seq->fps = fps;
  61. ff = malloc(sizeof(ffmpeg_codec_t));
  62. memset(ff, 0, sizeof(*ff));
  63. seq->codec_priv = ff;
  64. if (!initialised)
  65. {
  66. av_register_all();
  67. initialised = 1;
  68. }
  69. ff->fmt_ctx = avformat_alloc_context();
  70. if (!ff->fmt_ctx)
  71. goto error;
  72. /* Careful here: the Win32 snprintf doesn't seem to add a trailing
  73. * zero to the truncated output. */
  74. snprintf(ff->fmt_ctx->filename, sizeof(ff->fmt_ctx->filename),
  75. file);
  76. ff->fmt_ctx->filename[sizeof(ff->fmt_ctx->filename) - 1] = '\0';
  77. ff->fmt_ctx->oformat = guess_format(NULL, file, NULL);
  78. if (!ff->fmt_ctx->oformat)
  79. ff->fmt_ctx->oformat = guess_format("mpeg", NULL, NULL);
  80. if (!ff->fmt_ctx->oformat)
  81. goto error;
  82. ff->stream = av_new_stream(ff->fmt_ctx, 0);
  83. if (!ff->stream)
  84. goto error;
  85. ff->stream->sample_aspect_ratio.num = PAR_NUM;
  86. ff->stream->sample_aspect_ratio.den = PAR_DEN;
  87. ff->cod_ctx = ff->stream->codec;
  88. ff->cod_ctx->width = width;
  89. ff->cod_ctx->height = height;
  90. ff->cod_ctx->sample_aspect_ratio.num = PAR_NUM;
  91. ff->cod_ctx->sample_aspect_ratio.den = PAR_DEN;
  92. ff->cod_ctx->codec_id = ff->fmt_ctx->oformat->video_codec;
  93. ff->cod_ctx->codec_type = CODEC_TYPE_VIDEO;
  94. ff->cod_ctx->bit_rate = BITRATE;
  95. ff->cod_ctx->time_base.num = 1;
  96. ff->cod_ctx->time_base.den = fps;
  97. ff->cod_ctx->gop_size = fps * 3 / 4; /* empirical */
  98. ff->cod_ctx->pix_fmt = PIX_FMT_YUV420P; /* send YUV 420 */
  99. if (ff->cod_ctx->codec_id == CODEC_ID_MPEG2VIDEO)
  100. ff->cod_ctx->max_b_frames = 2;
  101. if (ff->cod_ctx->codec_id == CODEC_ID_MPEG1VIDEO)
  102. ff->cod_ctx->mb_decision = 2;
  103. if (ff->fmt_ctx->oformat->flags & AVFMT_GLOBALHEADER)
  104. ff->cod_ctx->flags |= CODEC_FLAG_GLOBAL_HEADER;
  105. if (av_set_parameters(ff->fmt_ctx, NULL) < 0)
  106. goto error;
  107. ff->codec = avcodec_find_encoder(ff->cod_ctx->codec_id);
  108. if (!ff->codec)
  109. goto error;
  110. if (avcodec_open(ff->cod_ctx, ff->codec) < 0)
  111. goto error;
  112. ff->frame = avcodec_alloc_frame();
  113. if (!ff->frame)
  114. goto error;
  115. tmp = (uint8_t *)av_malloc(avpicture_get_size(ff->cod_ctx->pix_fmt,
  116. ff->cod_ctx->width,
  117. ff->cod_ctx->height));
  118. if (!tmp)
  119. goto error;
  120. avpicture_fill((AVPicture *)ff->frame, tmp, ff->cod_ctx->pix_fmt,
  121. ff->cod_ctx->width, ff->cod_ctx->height);
  122. if (!(ff->fmt_ctx->flags & AVFMT_NOFILE))
  123. if (url_fopen(&ff->fmt_ctx->pb, file, URL_WRONLY) < 0)
  124. goto error;
  125. ff->buf_len = 64 * 1024 * 1024;
  126. ff->buf = (uint8_t *)av_malloc(ff->buf_len);
  127. av_write_header(ff->fmt_ctx);
  128. return seq;
  129. error:
  130. pipi_close_sequence(seq);
  131. return NULL;
  132. #else
  133. return NULL;
  134. #endif
  135. }
  136. int pipi_feed_sequence(pipi_sequence_t *seq, uint8_t *buffer, int width, int height)
  137. {
  138. #if defined USE_FFMPEG
  139. AVPacket packet;
  140. size_t bytes;
  141. int pitch;
  142. ffmpeg_codec_t *ff = (ffmpeg_codec_t *)seq->codec_priv;
  143. if (ff->src_width != width || ff->src_height != height)
  144. {
  145. ff->src_width = width;
  146. ff->src_height = height;
  147. if (ff->sws_ctx)
  148. sws_freeContext(ff->sws_ctx);
  149. ff->sws_ctx = NULL;
  150. }
  151. if (!ff->sws_ctx)
  152. ff->sws_ctx = sws_getContext(width, height, PIX_FMT_RGB32,
  153. ff->cod_ctx->width,
  154. ff->cod_ctx->height,
  155. ff->cod_ctx->pix_fmt, SWS_BICUBIC,
  156. NULL, NULL, NULL);
  157. if (!ff->sws_ctx)
  158. return -1;
  159. pitch = width * 4;
  160. sws_scale(ff->sws_ctx, &buffer, &pitch, 0, height,
  161. ff->frame->data, ff->frame->linesize);
  162. bytes = avcodec_encode_video(ff->cod_ctx, ff->buf,
  163. ff->buf_len, ff->frame);
  164. if (bytes <= 0)
  165. return 0;
  166. av_init_packet(&packet);
  167. if (ff->cod_ctx->coded_frame->pts != 0x8000000000000000LL)
  168. packet.pts = av_rescale_q(ff->cod_ctx->coded_frame->pts,
  169. ff->cod_ctx->time_base, ff->stream->time_base);
  170. if (ff->cod_ctx->coded_frame->key_frame)
  171. packet.flags |= PKT_FLAG_KEY;
  172. packet.stream_index = 0;
  173. packet.data = ff->buf;
  174. packet.size = bytes;
  175. if (av_interleaved_write_frame(ff->fmt_ctx, &packet) < 0)
  176. return -1;
  177. #endif
  178. return 0;
  179. }
  180. int pipi_close_sequence(pipi_sequence_t *seq)
  181. {
  182. #if defined USE_FFMPEG
  183. ffmpeg_codec_t *ff = (ffmpeg_codec_t *)seq->codec_priv;
  184. if (ff->fmt_ctx)
  185. {
  186. av_write_trailer(ff->fmt_ctx);
  187. }
  188. if (ff->buf)
  189. {
  190. av_free(ff->buf);
  191. ff->buf = NULL;
  192. }
  193. if (ff->cod_ctx)
  194. {
  195. avcodec_close(ff->cod_ctx);
  196. ff->cod_ctx = NULL;
  197. }
  198. if (ff->frame)
  199. {
  200. av_free(ff->frame->data[0]);
  201. av_free(ff->frame);
  202. ff->frame = NULL;
  203. }
  204. if (ff->fmt_ctx)
  205. {
  206. av_freep(&ff->fmt_ctx->streams[0]->codec);
  207. ff->codec = NULL;
  208. av_freep(&ff->fmt_ctx->streams[0]);
  209. ff->stream = NULL;
  210. if (!(ff->fmt_ctx->flags & AVFMT_NOFILE))
  211. url_fclose(ff->fmt_ctx->pb);
  212. av_free(ff->fmt_ctx);
  213. ff->fmt_ctx = NULL;
  214. }
  215. if (ff->sws_ctx)
  216. {
  217. sws_freeContext(ff->sws_ctx);
  218. ff->sws_ctx = NULL;
  219. ff->src_width = ff->src_height = 0;
  220. }
  221. free(ff);
  222. free(seq);
  223. #endif
  224. return 0;
  225. }