PageRenderTime 50ms CodeModel.GetById 18ms RepoModel.GetById 1ms app.codeStats 0ms

/amplayer/player/player_thumbnail.c

https://github.com/J1nx-Hackable-Gadgets/libamplayer-m3
C | 567 lines | 486 code | 76 blank | 5 comment | 115 complexity | 8a39d1e4865a76f3f2c0e8be3ca1458c MD5 | raw file
Possible License(s): LGPL-3.0, CC-BY-SA-3.0, GPL-2.0, GPL-3.0, LGPL-2.1
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <player_priv.h>
  4. #include <log_print.h>
  5. #include "thumbnail_type.h"
  6. static inline void calc_aspect_ratio(rational *ratio, struct stream *stream)
  7. {
  8. int num, den;
  9. av_reduce(&num, &den,
  10. stream->pCodecCtx->width * stream->pCodecCtx->sample_aspect_ratio.num,
  11. stream->pCodecCtx->height * stream->pCodecCtx->sample_aspect_ratio.den,
  12. 1024 * 1024);
  13. ratio->num = num;
  14. ratio->den = den;
  15. }
  16. static int av_read_next_video_frame(AVFormatContext *pFormatCtx, AVPacket *pkt,int vindex)
  17. {
  18. int r=-1;
  19. int retry=500;
  20. do{
  21. r = av_read_frame(pFormatCtx,pkt);
  22. if(r==0 && pkt->stream_index==vindex){
  23. break;
  24. }
  25. av_free_packet(pkt);
  26. if(r<0)
  27. break;
  28. else
  29. r=-2;/*a audio or other frame.*/
  30. }while(retry-->0);
  31. return r;
  32. }
  33. static void find_best_keyframe(AVFormatContext *pFormatCtx, int video_index, int count, int64_t *time, int64_t *offset, int *maxsize)
  34. {
  35. int i = 0;
  36. int maxFrameSize = 0;
  37. int64_t thumbTime = 0;
  38. int64_t thumbOffset = 0;
  39. AVPacket packet;
  40. int r = 0;
  41. int find_ok = 0;
  42. int keyframe_index=0;
  43. AVStream *st=pFormatCtx->streams[video_index];
  44. int havepts=0;
  45. int nopts=0;
  46. *maxsize=0;
  47. if(count<=0){
  48. float newcnt=-0.1;
  49. count=100;
  50. if(am_getconfig_float("libplayer.thumbnail.scan.count",&newcnt)>=0 && newcnt>=1)
  51. count=(int)newcnt;
  52. }
  53. do{
  54. r = av_read_next_video_frame(pFormatCtx, &packet,video_index);
  55. if(r<0)
  56. break;
  57. log_debug("[find_best_keyframe][%d]read frame packet.size=%d,pts=%lld\n",i,packet.size,packet.pts);
  58. havepts=(packet.pts>0||havepts);
  59. nopts=(i>10)&&!havepts;
  60. if (packet.size > maxFrameSize && (packet.pts>=0 || nopts)) { //packet.pts>=0 can used for seek.
  61. maxFrameSize = packet.size;
  62. thumbTime = packet.pts;
  63. thumbOffset = avio_tell(pFormatCtx->pb) - packet.size;
  64. keyframe_index=i;
  65. find_ok=1;
  66. }
  67. av_free_packet(&packet);
  68. if(i>5 && find_ok && maxFrameSize>100*1024/(1+i/2))
  69. break;
  70. }while(i++<count);
  71. if(find_ok){
  72. log_debug("[%s]return thumbTime=%lld thumbOffset=%llx\n", __FUNCTION__, thumbTime, thumbOffset);
  73. if(thumbTime>=0&&thumbTime != AV_NOPTS_VALUE)
  74. *time = av_rescale_q(thumbTime, st->time_base, AV_TIME_BASE_Q);
  75. else
  76. *time = AV_NOPTS_VALUE;
  77. *offset = thumbOffset;
  78. *maxsize = maxFrameSize;
  79. r=0;
  80. }else{
  81. log_print("[%s]find_best_keyframe failed\n", __FUNCTION__);
  82. }
  83. return r;
  84. }
  85. static void find_thumbnail_frame(AVFormatContext *pFormatCtx, int video_index, int64_t *thumb_time, int64_t *thumb_offset,int *pmaxframesize)
  86. {
  87. int64_t thumbTime = 0;
  88. int64_t thumbOffset = 0;
  89. AVPacket packet;
  90. AVStream *st = pFormatCtx->streams[video_index];
  91. int duration = pFormatCtx->duration / AV_TIME_BASE;
  92. /// int64_t init_seek_time = (duration > 0) ? MIN(10, duration >> 1) : 10;
  93. int64_t init_seek_time = (duration > 0) ? MIN(120, duration >> 1) : 10;
  94. int ret = 0;
  95. float starttime;
  96. int maxframesize;
  97. if(am_getconfig_float("libplayer.thumbnail.starttime",&starttime)>=0 && starttime>=0)
  98. {
  99. init_seek_time=(int64_t)starttime;
  100. if(init_seek_time >= duration)
  101. init_seek_time=duration-1;
  102. if(init_seek_time<=0)
  103. init_seek_time=0;
  104. }
  105. init_seek_time *= AV_TIME_BASE;
  106. log_debug("[find_thumbnail_frame]duration=%lld init_seek_time=%lld\n", pFormatCtx->duration, init_seek_time);
  107. //init_seek_time = av_rescale_q(init_seek_time, st->time_base, AV_TIME_BASE_Q);
  108. //log_debug("[find_thumbnail_frame]init_seek_time=%lld timebase=%d:%d video_index=%d\n",init_seek_time,st->time_base.num,st->time_base.den, video_index);
  109. ret = av_seek_frame(pFormatCtx, video_index,init_seek_time -100, 0);
  110. if (ret < 0) {
  111. avio_seek(pFormatCtx->pb, 0, SEEK_SET);
  112. log_error("[%s]seek error, reset offset to 0\n", __FUNCTION__);
  113. return;
  114. }
  115. log_debug("[find_thumbnail_frame]offset=%llx \n", avio_tell(pFormatCtx->pb));
  116. find_best_keyframe(pFormatCtx, video_index, 0, &thumbTime, &thumbOffset,&maxframesize);
  117. if (thumbTime != AV_NOPTS_VALUE) {
  118. *thumb_time = thumbTime;
  119. }else{
  120. *thumb_time = AV_NOPTS_VALUE;
  121. }
  122. *thumb_offset = thumbOffset;
  123. *pmaxframesize=maxframesize;
  124. log_debug("[find_thumbnail_frame]return thumb_time=%lld thumb_offset=%lld\n", *thumb_time, *thumb_offset);
  125. }
  126. void * thumbnail_res_alloc(void)
  127. {
  128. struct video_frame * frame;
  129. frame = (struct video_frame *)malloc(sizeof(struct video_frame));
  130. if (frame == NULL) {
  131. return NULL;
  132. }
  133. memset(frame, 0, sizeof(struct video_frame));
  134. av_register_all();
  135. return (void *)frame;
  136. }
  137. //#define DUMP_INDEX
  138. int thumbnail_find_stream_info(void *handle, const char* filename)
  139. {
  140. struct video_frame *frame = (struct video_frame *)handle;
  141. struct stream *stream = &frame->stream;
  142. if (av_open_input_file(&stream->pFormatCtx, filename, NULL, 0, NULL) != 0) {
  143. log_print("Coundn't open file %s !\n", filename);
  144. goto err;
  145. }
  146. if (av_find_stream_info(stream->pFormatCtx) < 0) {
  147. log_print("Coundn't find stream information !\n");
  148. goto err1;
  149. }
  150. #ifdef DUMP_INDEX
  151. int i, j;
  152. AVStream *pStream;
  153. log_print("*********************************************\n");
  154. for (i = 0; i < stream->pFormatCtx->nb_streams; i ++) {
  155. pStream = stream->pFormatCtx->streams[i];
  156. if (pStream) {
  157. for (j = 0; j < pStream->nb_index_entries; j++) {
  158. log_print("stream[%d]:idx[%d] pos:%llx time:%llx\n", i, j, pStream->index_entries[j].pos, pStream->index_entries[j].timestamp);
  159. }
  160. }
  161. }
  162. log_print("*********************************************\n");
  163. #endif
  164. return 0;
  165. err1:
  166. av_close_input_file(stream->pFormatCtx);
  167. err:
  168. memset(&frame->stream, 0, sizeof(struct stream));
  169. return -1;
  170. }
  171. int thumbnail_find_stream_info_end(void *handle)
  172. {
  173. struct video_frame *frame = (struct video_frame *)handle;
  174. struct stream *stream = &frame->stream;
  175. av_close_input_file(stream->pFormatCtx);
  176. return 0;
  177. }
  178. int thumbnail_decoder_open(void *handle, const char* filename)
  179. {
  180. int i;
  181. int video_index = -1;
  182. struct video_frame *frame = (struct video_frame *)handle;
  183. struct stream *stream = &frame->stream;
  184. log_debug("thumbnail open file:%s\n", filename);
  185. if (av_open_input_file(&stream->pFormatCtx, filename, NULL, 0, NULL) != 0) {
  186. log_print("Coundn't open file %s !\n", filename);
  187. goto err;
  188. }
  189. if (av_find_stream_info(stream->pFormatCtx) < 0) {
  190. log_print("Coundn't find stream information !\n");
  191. goto err1;
  192. }
  193. //dump_format(stream->pFormatCtx, 0, filename, 0);
  194. for (i = 0; i < stream->pFormatCtx->nb_streams; i++) {
  195. if (stream->pFormatCtx->streams[i]->codec->codec_type == CODEC_TYPE_VIDEO) {
  196. video_index = i;
  197. break;
  198. }
  199. }
  200. if (video_index == -1) {
  201. log_print("Didn't find a video stream!\n");
  202. goto err1;
  203. }
  204. find_thumbnail_frame(stream->pFormatCtx, video_index, &frame->thumbNailTime, &frame->thumbNailOffset,&frame->maxframesize);
  205. stream->videoStream = video_index;
  206. stream->pCodecCtx = stream->pFormatCtx->streams[video_index]->codec;
  207. if (stream->pCodecCtx == NULL) {
  208. log_print("pCodecCtx is NULL !\n");
  209. }
  210. frame->width = stream->pCodecCtx->width;
  211. frame->height = stream->pCodecCtx->height;
  212. stream->pCodec = avcodec_find_decoder(stream->pCodecCtx->codec_id);
  213. if (stream->pCodec == NULL) {
  214. log_print("Didn't find codec!\n");
  215. goto err1;
  216. }
  217. if (avcodec_open(stream->pCodecCtx, stream->pCodec) < 0) {
  218. log_print("Couldn't open codec!\n");
  219. goto err1;
  220. }
  221. frame->duration = stream->pFormatCtx->duration;
  222. stream->pFrameYUV = avcodec_alloc_frame();
  223. if (stream->pFrameYUV == NULL) {
  224. log_print("alloc YUV frame failed!\n");
  225. goto err2;
  226. }
  227. stream->pFrameRGB = avcodec_alloc_frame();
  228. if (stream->pFrameRGB == NULL) {
  229. log_print("alloc RGB frame failed!\n");
  230. goto err3;
  231. }
  232. frame->DataSize = avpicture_get_size(DEST_FMT, frame->width, frame->height);
  233. frame->data = (char *)malloc(frame->DataSize);
  234. if (frame->data == NULL) {
  235. log_print("alloc buffer failed!\n");
  236. goto err4;
  237. }
  238. avpicture_fill((AVPicture *)stream->pFrameRGB, frame->data, DEST_FMT, frame->width, frame->height);
  239. return 0;
  240. err4:
  241. av_free(stream->pFrameRGB);
  242. err3:
  243. av_free(stream->pFrameYUV);
  244. err2:
  245. avcodec_close(stream->pCodecCtx);
  246. err1:
  247. av_close_input_file(stream->pFormatCtx);
  248. err:
  249. memset(&frame->stream, 0, sizeof(struct stream));
  250. return -1;
  251. }
  252. int thumbnail_extract_video_frame(void *handle, int64_t time, int flag)
  253. {
  254. int frameFinished = 0;
  255. int tryNum = 0;
  256. int i = 0;
  257. int64_t ret;
  258. #define TRY_DECODE_MAX 30
  259. struct video_frame *frame = (struct video_frame *)handle;
  260. struct stream *stream = &frame->stream;
  261. AVFormatContext *pFormatCtx = stream->pFormatCtx;
  262. AVPacket packet;
  263. AVCodecContext *pCodecCtx = pFormatCtx->streams[stream->videoStream]->codec;
  264. int foundmaxframesize;
  265. if (time >= 0) {
  266. if (av_seek_frame(pFormatCtx, stream->videoStream, time-100, 0) < 0) {
  267. log_error("[thumbnail_extract_video_frame]av_seek_frame failed!");
  268. }
  269. find_best_keyframe(pFormatCtx, stream->videoStream, 0, &frame->thumbNailTime, &frame->thumbNailOffset,&frame->maxframesize);
  270. log_debug("[thumbnail_extract_video_frame:%d]time=%lld time=%lld offset=%lld!ret=%d\n",
  271. __LINE__,time, frame->thumbNailTime, frame->thumbNailOffset, ret);
  272. }
  273. if (frame->thumbNailTime>0 && frame->thumbNailTime != AV_NOPTS_VALUE) {
  274. int64_t seektime=frame->thumbNailTime-100;
  275. if(seektime<0) seektime=0;
  276. log_debug("seek to thumbnail frame by timestamp(%lld)!curoffset=%llx\n", seektime, avio_tell(pFormatCtx->pb));
  277. if (av_seek_frame(pFormatCtx, stream->videoStream, seektime, 0) < 0) {
  278. avio_seek(pFormatCtx->pb, frame->thumbNailOffset, 0);
  279. log_error("[thumbnail_extract_video_frame]av_seek_frame failed!seek to thumbNailOffset %x\n",frame->thumbNailOffset);
  280. }
  281. log_debug("after seek by time, offset=%llx!\n", avio_tell(pFormatCtx->pb));
  282. } else {
  283. log_debug("seek to thumbnail frame by offset(%lld)!\n", frame->thumbNailOffset);
  284. ret = avio_seek(pFormatCtx->pb, frame->thumbNailOffset, SEEK_SET);
  285. log_debug("after seek by offset, offset=%llx!ret=%llx\n", avio_tell(pFormatCtx->pb), ret);
  286. }
  287. avcodec_flush_buffers(stream->pCodecCtx);
  288. i=0;
  289. while (av_read_next_video_frame(pFormatCtx, &packet,stream->videoStream) >= 0) {
  290. AVFrame *pFrame=NULL;
  291. log_debug("[%s] av_read_frame frame size=%d,pts=%lld\n", __FUNCTION__, packet.size,packet.pts);
  292. i++;
  293. if(i<10 && packet.size<frame->maxframesize*9/10){
  294. continue;/*we have get the max framesize before,but the max frame is not I frame,maybe jumped,So I get a little one.*/
  295. }else if(packet.size<frame->maxframesize/2){
  296. continue;/*get 5 frames,still not get the better frame,maybe need try more smalls size.*/
  297. }if(packet.size<1024){
  298. continue;/*skip small size packets,it maybe a black frame*/
  299. }
  300. avcodec_decode_video2(stream->pCodecCtx, stream->pFrameYUV, &frameFinished, &packet);
  301. pFrame=stream->pFrameYUV ;
  302. log_debug("[%s]decode video frame, finish=%d key=%d offset=%llx type=%dcodec_id=%x,quality=%d tryNum=%d\n", __FUNCTION__,
  303. frameFinished, pFrame->key_frame, avio_tell(pFormatCtx->pb), pFrame->pict_type, pCodecCtx->codec_id,pFrame->quality,tryNum);
  304. if (frameFinished &&
  305. ((pFrame->key_frame && pFrame->pict_type == AV_PICTURE_TYPE_I) ||
  306. (pFrame->key_frame && pFrame->pict_type == AV_PICTURE_TYPE_SI) ||
  307. (pFrame->key_frame && pFrame->pict_type == AV_PICTURE_TYPE_BI) ||
  308. (tryNum>4 && pFrame->key_frame) ||
  309. (tryNum>5 && pFrame->pict_type == AV_PICTURE_TYPE_I) ||
  310. (tryNum>6 && pFrame->pict_type == AV_PICTURE_TYPE_SI) ||
  311. (tryNum>7 && pFrame->pict_type == AV_PICTURE_TYPE_BI) ||
  312. (tryNum>(TRY_DECODE_MAX-1) && pFrame->pict_type == AV_PICTURE_TYPE_P) ||
  313. (tryNum>(TRY_DECODE_MAX-1) && pFrame->pict_type == AV_PICTURE_TYPE_B) ||
  314. (tryNum>(TRY_DECODE_MAX-1) && pFrame->pict_type == AV_PICTURE_TYPE_S) ||
  315. (0))) /*not find a I FRAME too long,try normal frame*/
  316. {
  317. log_debug("[%s]pCodecCtx->codec_id=%x tryNum=%d\n", __FUNCTION__, pCodecCtx->codec_id, tryNum);
  318. struct SwsContext *img_convert_ctx;
  319. img_convert_ctx = sws_getContext(stream->pCodecCtx->width, stream->pCodecCtx->height,
  320. stream->pCodecCtx->pix_fmt,
  321. frame->width, frame->height, DEST_FMT, SWS_BICUBIC,
  322. NULL, NULL, NULL);
  323. if (img_convert_ctx == NULL) {
  324. log_print("can not initialize the coversion context!\n");
  325. av_free_packet(&packet);
  326. break;
  327. }
  328. sws_scale(img_convert_ctx, stream->pFrameYUV->data, stream->pFrameYUV->linesize, 0,
  329. frame->height, stream->pFrameRGB->data, stream->pFrameRGB->linesize);
  330. av_free_packet(&packet);
  331. goto ret;
  332. }
  333. av_free_packet(&packet);
  334. if(tryNum++>TRY_DECODE_MAX)
  335. break;
  336. if(tryNum%10==0)
  337. usleep(100);
  338. }
  339. if (frame->data) {
  340. free(frame->data);
  341. }
  342. av_free(stream->pFrameRGB);
  343. av_free(stream->pFrameYUV);
  344. avcodec_close(stream->pCodecCtx);
  345. av_close_input_file(stream->pFormatCtx);
  346. memset(&frame->stream, 0, sizeof(struct stream));
  347. return -1;
  348. ret:
  349. return 0;
  350. }
  351. int thumbnail_read_frame(void *handle, char* buffer)
  352. {
  353. int i;
  354. int index = 0;
  355. struct video_frame *frame = (struct video_frame *)handle;
  356. struct stream *stream = &frame->stream;
  357. for (i = 0; i < frame->height; i++) {
  358. memcpy(buffer + index, stream->pFrameRGB->data[0] + i * stream->pFrameRGB->linesize[0], frame->width * 2);
  359. index += frame->width * 2;
  360. }
  361. return 0;
  362. }
  363. void thumbnail_get_video_size(void *handle, int* width, int* height)
  364. {
  365. struct video_frame *frame = (struct video_frame *)handle;
  366. *width = frame->width;
  367. *height = frame->height;
  368. }
  369. float thumbnail_get_aspect_ratio(void *handle)
  370. {
  371. struct video_frame *frame = (struct video_frame *)handle;
  372. struct stream *stream = &frame->stream;
  373. calc_aspect_ratio(&frame->displayAspectRatio, stream);
  374. if (!frame->displayAspectRatio.num || !frame->displayAspectRatio.den) {
  375. return (float)frame->width / frame->height;
  376. } else {
  377. return (float)frame->displayAspectRatio.num / frame->displayAspectRatio.den;
  378. }
  379. }
  380. void thumbnail_get_duration(void *handle, int64_t *duration)
  381. {
  382. struct video_frame *frame = (struct video_frame *)handle;
  383. struct stream *stream = &frame->stream;
  384. *duration = stream->pFormatCtx->duration;
  385. }
  386. int thumbnail_get_key_metadata(void* handle, char* key, const char** value)
  387. {
  388. struct video_frame *frame = (struct video_frame *)handle;
  389. struct stream *stream = &frame->stream;
  390. AVDictionaryEntry *tag = NULL;
  391. if (!stream->pFormatCtx->metadata) {
  392. return 0;
  393. }
  394. if(!memcmp(key, "rotate", 6)) {
  395. int rot;
  396. thumbnail_get_video_rotation(handle,&rot);
  397. char *tmp = (char*)av_malloc(32);
  398. memset(tmp, 0x00, 32);
  399. sprintf(tmp, "%d", rot);
  400. *value = tmp;
  401. return 1;
  402. }
  403. tag = av_dict_get(stream->pFormatCtx->metadata, key, tag, 0);
  404. if (tag) {
  405. *value = tag->value;
  406. return 1;
  407. }
  408. return 0;
  409. }
  410. int thumbnail_get_key_data(void* handle, char* key, const void** data, int* data_size)
  411. {
  412. struct video_frame *frame = (struct video_frame *)handle;
  413. struct stream *stream = &frame->stream;
  414. AVDictionaryEntry *tag = NULL;
  415. if (!stream->pFormatCtx->metadata) {
  416. return 0;
  417. }
  418. if (av_dict_get(stream->pFormatCtx->metadata, key, tag, AV_METADATA_IGNORE_SUFFIX)) {
  419. *data = stream->pFormatCtx->cover_data;
  420. *data_size = stream->pFormatCtx->cover_data_len;
  421. return 1;
  422. }
  423. return 0;
  424. }
  425. int thumbnail_get_tracks_info(void *handle, int *vtracks, int *atracks, int *stracks)
  426. {
  427. struct video_frame *frame = (struct video_frame *)handle;
  428. struct stream *stream = &frame->stream;
  429. AVStream **avs = stream->pFormatCtx->streams;
  430. int i;
  431. *vtracks = 0;
  432. *atracks = 0;
  433. *stracks = 0;
  434. for (i = 0; i < stream->pFormatCtx->nb_streams; i++) {
  435. if (avs[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
  436. (*vtracks)++;
  437. } else if (avs[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
  438. (*atracks)++;
  439. } else if (avs[i]->codec->codec_type == AVMEDIA_TYPE_SUBTITLE) {
  440. (*stracks)++;
  441. } else
  442. ;
  443. }
  444. log_debug("thumbnail_get_tracks_info v:%d a:%d s:%d \n", *vtracks, *atracks, *stracks);
  445. return 0;
  446. }
  447. void thumbnail_get_video_rotation(void *handle, int* rotation)
  448. {
  449. struct video_frame *frame = (struct video_frame *)handle;
  450. struct stream *stream = &frame->stream;
  451. int stream_rotation = stream->pFormatCtx->streams[stream->videoStream]->rotation_degree;
  452. switch (stream_rotation) {
  453. case 1:
  454. *rotation = 90;
  455. break;
  456. case 2:
  457. *rotation = 180;
  458. break;
  459. case 3:
  460. *rotation = 270;
  461. break;
  462. default:
  463. *rotation = 0;
  464. break;
  465. }
  466. return;
  467. }
  468. int thumbnail_decoder_close(void *handle)
  469. {
  470. struct video_frame *frame = (struct video_frame *)handle;
  471. struct stream *stream = &frame->stream;
  472. if (frame->data) {
  473. free(frame->data);
  474. }
  475. if (stream->pFrameRGB) {
  476. av_free(stream->pFrameRGB);
  477. }
  478. if (stream->pFrameYUV) {
  479. av_free(stream->pFrameYUV);
  480. }
  481. avcodec_close(stream->pCodecCtx);
  482. av_close_input_file(stream->pFormatCtx);
  483. return 0;
  484. }
  485. void thumbnail_res_free(void* handle)
  486. {
  487. struct video_frame *frame = (struct video_frame *)handle;
  488. if (frame) {
  489. free(frame);
  490. }
  491. }