• 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;  
  • 相关阅读:
    nginx 开启 gzip 压缩
    React Native 开发豆瓣评分(八)首页开发
    flutter报错--ProcessException: Process... gradlew.bat ...exited abnormally
    React Native 开发豆瓣评分(七)首页组件开发
    React Native 开发豆瓣评分(六)添加字体图标
    React Native 开发豆瓣评分(五)屏幕适配方案
    随笔
    MySQL的安装与配置
    mybatisXMLsql
    数据类型转换
  • 原文地址:https://www.cnblogs.com/boonya/p/8571885.html
Copyright © 2020-2023  润新知