zoukankan      html  css  js  c++  java
  • FFmpeg 如何探测网络流格式/如何从内存中获取数据

    文章转自:http://blog.csdn.net/rootusers/article/details/42551935

    一般ffmpeg都是直接从文件中读取或者从网络流中读取,比如rtp://xx.xx.xx.xx:xxxx。

    事实上也支持从内存中获取。

    函数avio_alloc_context()实现该功能。

    1. AVIOContext *avio_alloc_context(  
    2.                   unsigned char *buffer,  
    3.                   int buffer_size,  
    4.                   int write_flag,  
    5.                   void *opaque,  
    6.                   int (*read_packet)(void *opaque, uint8_t *buf, int buf_size),//重写该函数,指定从内存中读取的方法,将buf_size字节大小的数据保存到buf  
    7.                   int (*write_packet)(void *opaque, uint8_t *buf, int buf_size),//对应的这是写内存的函数  
    8.                   int64_t (*seek)(void *opaque, int64_t offset, int whence));  

    对于探测网络媒体流个格式,也可以用此种方法,先接收数据,然后探测。

    下面贴出代码:

    1. /* 
    2. *author tongli 
    3. */  
    4. extern "C"{  
    5. #include "libavformat/avformat.h"  
    6. #include "libavcodec/avcodec.h"  
    7. #include "libavutil/avutil.h"  
    8. }  
    9. #define BUF_SIZE 4096*500  
    10.   
    11. FILE* file;  
    12. //实现read_packet函数,从文件中读取模拟的是从内存中获取,同样可以实现为接收网络流  
    13. int read_packet(void *opaque, uint8_t *buf, int buf_size)  
    14. {  
    15.     int n = 0;  
    16.     if (!feof(file)){  
    17.         n = fread(buf, 1, buf_size, file);  
    18.         return n;  
    19.     }else  
    20.         return -1;  
    21. }  
    22.   
    23. int main(int argc, char** argv)  
    24. {  
    25.     file = fopen("2.mp4", "rb");  
    26.     if (file == NULL)  
    27.         return -1;  
    28.     av_register_all();  
    29.     AVIOContext* pb = NULL;  
    30.     AVInputFormat* piFmt = NULL;  
    31.     AVInputFormat* pFmt = NULL;  
    32.   
    33.     uint8_t* buf = (uint8_t*)av_mallocz(sizeof(uint8_t)* BUF_SIZE);  
    34.   
    35.     pb = avio_alloc_context(buf, BUF_SIZE, 0, NULL, read_packet, NULL, NULL);  
    36.     if (av_probe_input_buffer(pb, &piFmt, "", NULL, 0, 0) < 0)//探测从内存中获取到的媒体流的格式  
    37.     {  
    38.         fprintf(stderr, "probe format failed ");  
    39.         return -1;   
    40.     }  
    41.     else{  
    42.         fprintf(stdout, "format:%s[%s] ", piFmt->name, piFmt->long_name);  
    43.     }  
    44.     return 0;  
    45. }  


    下面实现一个简单的例子,从内存中读取,然后播放。

      1. <pre name="code" class="cpp">/* 
      2. *author tongli 
      3. */  
      4. #include <stdio.h>  
      5. #include <direct.h>  
      6. #include <io.h>  
      7. extern "C"{  
      8. #include "libavformat/avformat.h"  
      9. #include "libavcodec/avcodec.h"  
      10. #include "libavutil/avutil.h"  
      11. #include "libswscale/swscale.h"  
      12. #include "libavformat/avio.h"  
      13. #include "sdl/SDL.h"  
      14. }  
      15. #define BUF_SIZE 4096 * 500  
      16. FILE* file;  
      17.   
      18. int read_data(void *opaque, uint8_t *buf, int buf_size)  
      19. {  
      20.     int n = 0;  
      21.     if (!feof(file)){  
      22.         n = fread(buf, 1, buf_size, file);  
      23.         return n;  
      24.     }  
      25.     else  
      26.         return -1;  
      27. }  
      28.   
      29. int main(int argc, char* argv[])  
      30. {  
      31.     av_register_all();  
      32.     //file = fopen("h2.dat", "rb");  
      33.     file = fopen("3.mp4", "rb+");  
      34.     if (file == NULL)  
      35.         return -1;  
      36.     AVFormatContext *pFormatCtx;  
      37.     int             i, videoindex;  
      38.     AVCodecContext  *pCodecCtx;  
      39.     AVCodec         *pCodec;  
      40.     AVIOContext* pb = NULL;  
      41.     AVInputFormat* piFmt = NULL;  
      42.   
      43.     uint8_t* buf = (uint8_t*)av_mallocz(sizeof(uint8_t)* BUF_SIZE);  
      44.   
      45.     pb = avio_alloc_context(buf, BUF_SIZE, 0, NULL, read_data, NULL, NULL);  
      46.     if (av_probe_input_buffer(pb, &piFmt, "", NULL, 0, 0) < 0)  
      47.     {  
      48.         fprintf(stderr, "probe format failed ");  
      49.         return -1;  
      50.     }  
      51.     else{  
      52.         fprintf(stdout, "format:%s[%s] ", piFmt->name, piFmt->long_name);  
      53.     }  
      54.     pFormatCtx = avformat_alloc_context();  
      55.     pFormatCtx->pb = pb;  
      56.   
      57.     if (avformat_open_input(&pFormatCtx, "", piFmt, NULL) != 0){//iformat,priv_data赋值,pb, nbstreams,streams为null  
      58.         printf("Couldn't open input stream.(无法打开输入流) ");  
      59.         return -1;  
      60.     }  
      61.     if (avformat_find_stream_info(pFormatCtx, NULL)<0)//nbstreams,streams赋值, pb还是为null  
      62.     {  
      63.         printf("Couldn't find stream information.(无法获取流信息) ");  
      64.         return -1;  
      65.     }  
      66.     videoindex = -1;  
      67.     for (i = 0; i<pFormatCtx->nb_streams; i++) //一般情况下,一个媒体只有两个流,视频和音频流即streams[0],stream[1]  
      68.     if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)  
      69.     {//找到视频流  
      70.         videoindex = i;//在nb_streams视频流的索引  
      71.         break;  
      72.     }  
      73.     if (videoindex == -1)  
      74.     {  
      75.         printf("Didn't find a video stream.(没有找到视频流) ");  
      76.         return -1;  
      77.     }  
      78.     pCodecCtx = pFormatCtx->streams[videoindex]->codec;  
      79.     pCodec = avcodec_find_decoder(pCodecCtx->codec_id);  
      80.     if (pCodec == NULL)  
      81.     {  
      82.         printf("Codec not found.(没有找到解码器) ");  
      83.         return -1;  
      84.     }  
      85.     if (avcodec_open2(pCodecCtx, pCodec, NULL)<0)  
      86.     {  
      87.         printf("Could not open codec.(无法打开解码器) ");  
      88.         return -1;  
      89.     }  
      90.     AVFrame *pFrame, *pFrameYUV;  
      91.     pFrame = av_frame_alloc();  
      92.     pFrameYUV = av_frame_alloc();  
      93.   
      94.     uint8_t *out_buffer;  
      95.     out_buffer = new uint8_t[avpicture_get_size(PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height)];  
      96.       
      97.     avpicture_fill((AVPicture *)pFrameYUV, out_buffer, PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height);  
      98.     //------------SDL----------------  
      99.     if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER)) {  
      100.         printf("Could not initialize SDL - %s ", SDL_GetError());  
      101.         return -1;  
      102.     }  
      103.     SDL_Surface *screen;  
      104.     screen = SDL_SetVideoMode(pCodecCtx->width, pCodecCtx->height, 0, 0);  
      105.     if (!screen) {  
      106.         printf("SDL: could not set video mode - exiting ");  
      107.         return -1;  
      108.     }  
      109.     SDL_Overlay *bmp;  
      110.     bmp = SDL_CreateYUVOverlay(pCodecCtx->width, pCodecCtx->height, SDL_YV12_OVERLAY, screen);  
      111.     SDL_Rect rect;  
      112.     //---------------  
      113.     int ret, got_picture;  
      114.     int y_size = pCodecCtx->width * pCodecCtx->height;  
      115.   
      116.     AVPacket *packet = (AVPacket *)av_malloc(sizeof(AVPacket));  
      117.     av_new_packet(packet, y_size);  
      118.   
      119.     struct SwsContext *img_convert_ctx;  
      120.     img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height,  
      121.         AV_PIX_FMT_YUVJ420P/*pCodecCtx->pix_fmt*/, pCodecCtx->width, pCodecCtx->height,  
      122.         PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL);  
      123.     //------------------------------  
      124.     while (av_read_frame(pFormatCtx, packet) >= 0)  
      125.     {  
      126.         if (packet->stream_index == videoindex)  
      127.         {  
      128.             ret = avcodec_decode_video2(pCodecCtx, pFrame, &got_picture, packet);  
      129.             if (ret < 0)  
      130.             {  
      131.                 printf("Decode Error.(解码错误) ");  
      132.                 return -1;  
      133.             }  
      134.             if (got_picture)  
      135.             {  
      136.                 sws_scale(img_convert_ctx, (const uint8_t* const*)pFrame->data, pFrame->linesize, 0, pCodecCtx->height, pFrameYUV->data, pFrameYUV->linesize);  
      137.   
      138.                 SDL_LockYUVOverlay(bmp);  
      139.                 bmp->pixels[0] = pFrameYUV->data[0];  
      140.                 bmp->pixels[2] = pFrameYUV->data[1];  
      141.                 bmp->pixels[1] = pFrameYUV->data[2];  
      142.                 bmp->pitches[0] = pFrameYUV->linesize[0];  
      143.                 bmp->pitches[2] = pFrameYUV->linesize[1];  
      144.                 bmp->pitches[1] = pFrameYUV->linesize[2];  
      145.                 SDL_UnlockYUVOverlay(bmp);  
      146.                 rect.x = 0;  
      147.                 rect.y = 0;  
      148.                 rect.w = pCodecCtx->width;  
      149.                 rect.h = pCodecCtx->height;  
      150.                 SDL_DisplayYUVOverlay(bmp, &rect);  
      151.                 //延时40ms  
      152.                 SDL_Delay(40);  
      153.             }  
      154.         }  
      155.         av_free_packet(packet);  
      156.     }  
      157.     sws_freeContext(img_convert_ctx);  
      158.   
      159.     delete[] out_buffer;  
      160.     av_free(pFrameYUV);  
      161.     avcodec_close(pCodecCtx);  
      162.     avformat_close_input(&pFormatCtx);  
      163.   
      164.     return 0;  
  • 相关阅读:
    mysql报错:java.sql.SQLException: The server time zone value 'Öйú±ê׼ʱ¼ä' is unrecognized or represents more than one time zone.
    MD5登陆密码的生成
    15. 3Sum、16. 3Sum Closest和18. 4Sum
    11. Container With Most Water
    8. String to Integer (atoi)
    6. ZigZag Conversion
    5. Longest Palindromic Substring
    几种非线性激活函数介绍
    AI初探1
    AI初探
  • 原文地址:https://www.cnblogs.com/boonya/p/8571885.html
Copyright © 2011-2022 走看看