2015-09-07 107 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; 
}