2015-09-07 58 views
0

我想在一台计算机上生成视频帧并将它们传输到另一台计算机上进行处理和显示。我想以编程方式进行此操作,因为源图像是从第三方C++库生成的,而在接收端,我想在显示它们之前操作图像。我试图用FFMPEG拉我的头发。我得到了编码示例,但不知道该做什么。我刚刚搜索了所有我能想到的东西,但无法找出一旦填充了AVPacket,就要调用哪个FFMPEG库/函数。看来我需要使用AVIO或AVFormat或复用器,但不清楚如何初始化并使其工作。我希望你能提供任何帮助。FFMPEG通过网络流式传输图片系列

为了提供一些上下文,我提供了ffmpeg工作提供的示例'decode_encoding.c'。这里是我正在努力的地方:

 /* encode the image */ 
     ret = avcodec_encode_video2(c, &pkt, frame, &got_output); 
     if (ret < 0) { 
      fprintf(stderr, "Error encoding frame\n"); 
      exit(1); 
     } 

     if (got_output) { 
      printf("Write frame %3d (size=%5d)\n", i, pkt.size); 
      fwrite(pkt.data, 1, pkt.size, f); 

      // 
      // instead of writing to a file, i want to stream to a network 
      // What do I need to do with pkt to do that? 
      // 
      av_free_packet(&pkt); 
     } 

大多数文档(和Dranger教程)重点阅读和写入文件。我不需要使用文件。我想通过网络流式传输视频。看起来我需要AVFormat和AVio,但我只是无法弄清楚它们是如何融合在一起的。

+1

从dranger教程http://dranger.com/ffmpeg开始。之后,如果您仍然遇到问题,请指出无法使用的特定步骤。 – szatmary

+0

@szatmary,我明白了。谢谢。 – Commodore63

回答

1

关键是使用avio_open2()打开套接字连接,然后将pkt的数据和大小字段传递给avio_write()。他是一个示例工作程序(源自ffmpeg的doc/examples目录中的decode_encode.c):

#include "stdafx.h" 
/* 
* Copyright (c) 2001 Fabrice Bellard 
* 
* Permission is hereby granted, free of charge, to any person obtaining a copy 
* of this software and associated documentation files (the "Software"), to deal 
* in the Software without restriction, including without limitation the rights 
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
* copies of the Software, and to permit persons to whom the Software is 
* furnished to do so, subject to the following conditions: 
* 
* The above copyright notice and this permission notice shall be included in 
* all copies or substantial portions of the Software. 
* 
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 
* THE SOFTWARE. 
*/ 

/** 
* @file 
* libavcodec API use example. 
* 
* @example decoding_encoding.c 
* Note that libavcodec only handles codecs (mpeg, mpeg4, etc...), 
* not file formats (avi, vob, mp4, mov, mkv, mxf, flv, mpegts, mpegps, etc...). See library 'libavformat' for the 
* format handling 
*/ 

#include <math.h> 
#include <stdio.h> 
#include <cstdio> 
#include <winsock.h> 

extern "C" 
{ 
#include <libavutil/opt.h> 
#include <libavcodec/avcodec.h> 
#include <libavutil/channel_layout.h> 
#include <libavutil/common.h> 
#include <libavutil/imgutils.h> 
#include <libavutil/mathematics.h> 
#include <libavutil/samplefmt.h> 
#include <libavformat\avio.h> 
#include <libavformat\avformat.h> 
} 

#define INBUF_SIZE 4096 
#define AUDIO_INBUF_SIZE 20480 
#define AUDIO_REFILL_THRESH 4096 


static void video_encode_example(const char *filename, AVCodecID codec_id) 
{ 
    AVCodec *codec; 
    AVCodecContext *c = NULL; 
    int i, ret, x, y, got_output; 
    FILE *f; 
    AVFrame *frame; 
    AVPacket pkt; 
    uint8_t endcode[] = { 0, 0, 1, 0xb7 }; 
    errno_t err; 
    int errval; 
    printf("Encode video file %s\n", filename); 

    /* find the mpeg1 video encoder */ 
    codec = avcodec_find_encoder(codec_id); 
    if (!codec) { 
     fprintf(stderr, "Codec not found\n"); 
     exit(1); 
    } 

    c = avcodec_alloc_context3(codec); 
    if (!c) { 
     fprintf(stderr, "Could not allocate video codec context\n"); 
     exit(1); 
    } 

    /* put sample parameters */ 
    c->bit_rate = 4000000; 
    /* resolution must be a multiple of two */ 
    c->width = 1024; 
    c->height = 768; 
    /* frames per second */ 
    c->time_base.den = 25; 
    c->time_base.num = 1; 
    /* emit one intra frame every ten frames 
    * check frame pict_type before passing frame 
    * to encoder, if frame->pict_type is AV_PICTURE_TYPE_I 
    * then gop_size is ignored and the output of encoder 
    * will always be I frame irrespective to gop_size 
    */ 
    c->gop_size = 12; 
    c->max_b_frames = 0; 
    c->pix_fmt = AV_PIX_FMT_YUV420P; 

    if (codec_id == AV_CODEC_ID_H264) 
    { 
     av_opt_set(c->priv_data, "preset", "slow", 0); 
     av_opt_set(c->priv_data, "tune", "zerolatency", 0); 
    } 

    /* open it */ 
    if (avcodec_open2(c, codec, NULL) < 0) { 
     fprintf(stderr, "Could not open codec\n"); 
     exit(1); 
    } 

    AVFormatContext* format = avformat_alloc_context(); 
    AVDictionary *options = NULL; 
    av_dict_set(&options, "pkt_size", "1300", 0); 
    av_dict_set(&options, "buffer_size", "65535", 0); 
    AVIOContext * server = NULL; 
    avio_open2(&server, "udp://192.168.0.13:5555", AVIO_FLAG_WRITE, NULL, &options); 

    frame = av_frame_alloc(); 
    if (!frame) { 
     fprintf(stderr, "Could not allocate video frame\n"); 
     exit(1); 
    } 
    frame->format = c->pix_fmt; 
    frame->width = c->width; 
    frame->height = c->height; 

    /* the image can be allocated by any means and av_image_alloc() is 
    * just the most convenient way if av_malloc() is to be used */ 
    ret = av_image_alloc(frame->data, frame->linesize, c->width, c->height, 
     c->pix_fmt, 32); 
    if (ret < 0) { 
     fprintf(stderr, "Could not allocate raw picture buffer\n"); 
     exit(1); 
    } 
    // Cycle through the test pattern for 1 hour 
    for (int j = 0; j < 3600; j++) 
    { 
     /* encode 1 second of video */ 
     for (i = 0; i < 25; i++) { 

      Sleep(40); 
      av_init_packet(&pkt); 
      pkt.data = NULL; // packet data will be allocated by the encoder 
      pkt.size = 1300; 

      fflush(stdout); 
      /* prepare a dummy image */ 
      /* Y */ 
      for (y = 0; y < c->height; y++) { 
       for (x = 0; x < c->width; x++) { 
        frame->data[0][y * frame->linesize[0] + x] = x + y + i * 3; 
       } 
      } 

      /* Cb and Cr */ 
      for (y = 0; y < c->height/2; y++) { 
       for (x = 0; x < c->width/2; x++) { 
        frame->data[1][y * frame->linesize[1] + x] = 128 + y + i * 2; 
        frame->data[2][y * frame->linesize[2] + x] = 64 + x + i * 5; 
       } 
      } 

      frame->pts = i+j*25; 

      /* encode the image */ 
      ret = avcodec_encode_video2(c, &pkt, frame, &got_output); 
      if (ret < 0) { 
       fprintf(stderr, "Error encoding frame\n"); 
       exit(1); 
      } 

      if (got_output) { 
       printf("Write frame %3d (size=%5d)\n", i, pkt.size); 
       //fwrite(pkt.data, 1, pkt.size, f); 
       avio_write(server, pkt.data, pkt.size); 
       av_free_packet(&pkt); 
      } 
     } 
    } 

    /* get the delayed frames */ 
    for (got_output = 1; got_output; i++) { 
     fflush(stdout); 

     ret = avcodec_encode_video2(c, &pkt, NULL, &got_output); 
     if (ret < 0) { 
      fprintf(stderr, "Error encoding frame\n"); 
      exit(1); 
     } 

     if (got_output) { 
      printf("Write frame %3d (size=%5d)\n", i, pkt.size); 
      avio_write(server, pkt.data, pkt.size); 
      av_free_packet(&pkt); 
     } 
    } 
    avcodec_close(c); 
    av_free(c); 
    av_freep(&frame->data[0]); 
    av_frame_free(&frame); 
    printf("\n"); 
} 

int main(int argc, char **argv) 
{ 
    const char *output_type; 

    /* register all the codecs */ 
    av_register_all(); 
    avcodec_register_all(); 
    avformat_network_init(); 

    video_encode_example("test.h264", AV_CODEC_ID_H264); 

    return 0; 
}