2016-11-27 3 views
3

I 인코딩려고 스트림 FFmpeg를 사용 (위해 libavcodec/libavformat을 - Zeranoe와 MSVC x64의 빌드) 생성 여기 는 FFmpeg은 RTP 스트림

크게 부호화 예에서 적응 내 코드이며, 에러 처리가

제거
#include "stdafx.h" 
extern "C" { 
#include <libavformat/avformat.h> 
#include <libavcodec/avcodec.h> 

#include <libavutil/opt.h> 
#include <libavutil/channel_layout.h> 
#include <libavutil/common.h> 
#include <libavutil/imgutils.h> 
#include <libavutil/mathematics.h> 
#include <libavutil/samplefmt.h> 
} 
#pragma comment(lib, "avformat.lib") 
#pragma comment(lib, "avutil.lib") 
#pragma comment(lib, "avcodec.lib") 

int main() { 
    avcodec_register_all(); 
    av_register_all(); 
    avformat_network_init(); 

    AVCodecID codec_id = AV_CODEC_ID_H264; 
    AVCodec *codec; 
    AVCodecContext *c = NULL; 
    int i, ret, x, y, got_output; 
    AVFrame *frame; 
    AVPacket pkt; 

    codec = avcodec_find_encoder(codec_id); 
    c = avcodec_alloc_context3(codec); 

    c->bit_rate = 400000; 
    c->width = 352; 
    c->height = 288; 
    c->time_base.num = 1; 
    c->time_base.den = 25; 
    c->gop_size = 25; 
    c->max_b_frames = 1; 
    c->pix_fmt = AV_PIX_FMT_YUV420P; 
    c->codec_type = AVMEDIA_TYPE_VIDEO; 
    c->flags = CODEC_FLAG_GLOBAL_HEADER; 

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

    avcodec_open2(c, codec, NULL) 

    frame = av_frame_alloc(); 
    frame->format = c->pix_fmt; 
    frame->width = c->width; 
    frame->height = c->height; 
    ret = av_image_alloc(frame->data, frame->linesize, c->width, c->height, 
     c->pix_fmt, 32); 

    AVFormatContext* avfctx; 
    AVOutputFormat* fmt = av_guess_format("rtp", NULL, NULL); 

    ret = avformat_alloc_output_context2(&avfctx, fmt, fmt->name, 
     "rtp://127.0.0.1:49990"); 

    printf("Writing to %s\n", avfctx->filename); 

    avio_open(&avfctx->pb, avfctx->filename, AVIO_FLAG_WRITE) 

    struct AVStream* stream = avformat_new_stream(avfctx, codec); 
    stream->codecpar->bit_rate = 400000; 
    stream->codecpar->width = 352; 
    stream->codecpar->height = 288; 
    stream->codecpar->codec_id = AV_CODEC_ID_H264; 
    stream->codecpar->codec_type = AVMEDIA_TYPE_VIDEO; 
    stream->time_base.num = 1; 
    stream->time_base.den = 25; 

    avformat_write_header(avfctx, NULL); 
    char buf[200000]; 
    AVFormatContext *ac[] = { avfctx }; 
    av_sdp_create(ac, 1, buf, 20000); 
    printf("sdp:\n%s\n", buf); 
    FILE* fsdp; 
    fopen_s(&fsdp, "test.sdp", "w"); 
    fprintf(fsdp, "%s", buf); 
    fclose(fsdp); 
    system("PAUSE"); 
    system("start "" \"C:\\Program Files (x86)\\VideoLAN\\VLC\\vlc.exe\" test.sdp"); 

    int j = 0; 
    for (i = 0; i < 10000; i++) { 
     av_init_packet(&pkt); 
     pkt.data = NULL; // packet data will be allocated by the encoder 
     pkt.size = 0; 
     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; 
     /* encode the image */ 
     ret = avcodec_send_frame(c, frame); 
     ret = avcodec_receive_packet(c, &pkt); 

     if (ret == AVERROR_EOF) { 
      got_output = false; 
      printf("Stream EOF\n"); 
     } else if(ret == AVERROR(EAGAIN)) { 
      got_output = false; 
      printf("Stream EAGAIN\n"); 
     } else { 
      got_output = true; 
     } 

     if (got_output) { 
      printf("Write frame %3d (size=%5d)\n", j++, pkt.size); 
      av_interleaved_write_frame(avfctx, &pkt); 
      av_packet_unref(&pkt); 
     } 

     Sleep(40); 
    } 

    // end 
    ret = avcodec_send_frame(c, NULL); 

    /* get the delayed frames */ 
    for (; ; i++) { 
     fflush(stdout); 
     ret = avcodec_receive_packet(c, &pkt); 
     if (ret == AVERROR_EOF) { 
      printf("Stream EOF\n"); 
      break; 
     } else if (ret == AVERROR(EAGAIN)) { 
      printf("Stream EAGAIN\n"); 
      got_output = false; 
     } else { 
      got_output = true; 
     } 

     if (got_output) { 
      printf("Write frame %3d (size=%5d)\n", j++, pkt.size); 
      av_interleaved_write_frame(avfctx, &pkt); 
      av_packet_unref(&pkt); 
     } 
    } 

    avcodec_close(c); 
    av_free(c); 
    av_freep(&frame->data[0]); 
    av_frame_free(&frame); 
    printf("\n"); 
    system("pause"); 
    return 0; 
} 

그러나 VLC (생성 된 SDP 파일로 열림)는 스트림을 재생할 수 없습니다. 이

core error: ES_OUT_RESET_PCR called 

는 다음 메시지가있다 내가 잘못 뭐하는 거지

packetizer_h264 warning: waiting for SPS/PPS 
core debug: Buffering <some percent>% 

반복? 각 이제 av_interleaved_write_frame

VLC 재생하기 전에 CODEC_FLAG_GLOBAL_HEADER 플래그

  • 을 사용 avformat_write_header를 사용하지 마십시오

    1. :

  • 답변

    1

    이는 FFmpeg 소스에 파고의 몇 시간 후, 나는 해결책을 발견 스트림이 정확하게

    +0

    코덱 'AV_CODEC_FLAG_GLOBAL_HEADER' 플래그는 muxer 설명에 플래그 AVFMT_GL이 포함 된 경우에만 설정해야합니다 OBALHEADER'. rtp의 경우 설정되지 않습니다. codecpar를 수동으로 채우는 대신'avcodec_parameters_from_context'를 사용하는 것이 훨씬 낫습니다. 그리고 시작시'avformat_write_header'를 한 번만 호출해야합니다. 당신이 그것을 반복적으로해야한다면, 당신은 뭔가 잘못하고있는 것입니다. –

    +0

    @AndreyTurkin 'avcodec_parameters_from_context'를 사용하도록 변경했습니다. 그러나 avformat_write_header가 반복적으로 호출되지 않으면 VLC는 스트림을 재생하지 않고 (버퍼링 0 %에서 멈춤) gstreamer가 지연합니다 (더 구체적으로 말하면,'avformat_write_header'가 x 시간 간격으로 호출되면 gstreamer는 반복적으로 멈추게됩니다). x 시간 (최대 1 초). 나는 내가 뭘 잘못하고 있는지 알고 싶다. – DankMemes