葡京网投哪个正规 > 首页 > iOS使用ffmpeg播放rstp实时监控视频数据流,搞了一周葡京网投哪个正规:

原标题:iOS使用ffmpeg播放rstp实时监控视频数据流,搞了一周葡京网投哪个正规:

浏览次数:149 时间:2019-11-30

iOS使用ffmpeg播放rstp实时监控视频数据流

一、编译针对iOS平台的ffmpeg库(kxmovie) 近期有一个项目,需要播放各种格式的音频、视频以及网络摄像头实时监控的视频流数据,经过多种折腾之后,最后选择了kxmovie,kxmovie项目已经整合了ffmpeg和简单的播放器,具体可以参考kxmovie主页: 编译kxmovie很简单,已经支持iOS 6.1 和 armv7s,一次成功,编译过程没出现什么问题:

git clone git://github.com/kolyvan/kxmovie.git

cd kxmovie

git submodule update --init 

rake

二、使用kxmovie 1.把kxmovie/output文件夹下文件添加到工程 2.添加框架:MediaPlayer, CoreAudio, AudioToolbox, Accelerate, QuartzCore, OpenGLES and libz.dylib,libiconv.dylib 3.添加lib库:libkxmovie.a, libavcodec.a, libavformat.a, libavutil.a, libswscale.a, libswresample.a 4.播放视频:

ViewController *vc;
    vc = [KxMovieViewController movieViewControllerWithContentPath:path parameters:nil];
    [self presentViewController:vc animated:YES completion:nil]; 

5.具体使用参考demo工程:KxMovieExample 三、碰到的问题 播放本地视频和网络视频正常,播放网络摄像头实时监控视频流(h264)的时候出现错误:

[rtsp @ 0x906cc00] UDP timeout, retrying with TCP

[rtsp @ 0x906cc00] Nonmatching transport in server reply

[rtsp @ 0x906cc00] Could not find codec parameters for stream 0 (Video: h264): unspecified size

Consider increasing the value for the 'analyzeduration' and 'probesize' options

Couldn't find stream information

跟踪代码,错误是在avformat_find_stream_info获取流信息失败的时候的时候触发。

if(avformat_find_stream_info(pFormatCtx,NULL) < 0) {

av_log(NULL, AV_LOG_ERROR, "Couldn't find stream informationn");

goto initError;

}

经过几天的摸索,最终确定是网络的问题(在模拟器播放一直出错,在3G网络下能播放葡京正网网投 1),具体原因估计是rstp视频流,程序默认采用udp传输或者组播,导致在私有网络视频流不能正常传输。 解决方法,把视频流的传输模式强制成tcp传输:

……

// Open video file

pFormatCtx = avformat_alloc_context();

//有三种传输方式:tcp udp_multicast udp,强制采用tcp传输

AVDictionary* options = NULL;

av_dict_set(&options, "rtsp_transport", "tcp", 0);

if(avformat_open_input(&pFormatCtx, [moviePathcStringUsingEncoding:NSASCIIStringEncoding], NULL,&options) != 0) {

av_log(NULL, AV_LOG_ERROR, "Couldn't open filen");

goto initError;

}

// Retrieve stream information

if(avformat_find_stream_info(pFormatCtx,NULL) < 0) {

av_log(NULL, AV_LOG_ERROR, "Couldn't find stream informationn");

goto initError;

} ……

一、编译针对iOS平台的ffmpeg库(kxmovie)近期有一个项目,需要播放各种式的音频、视频以及网络摄...

}else{

葡京正网网投 2

from:

// Write pixel data

有点兴奋,一周的成果,不容易呀,真心的。

 

//解码后的视频帧数据保存在pFrame变量中,然后经过swscale函数转换后,将视频帧数据保存在pFrameYUV变量中。最后将pFrameYUV中的数据写入成文件。AVFrame *pFrameYUV

程序由三个线程组成: 一个采集并编码线程;一个将编码后的数据推送至rtsp264线程;一个主线程。线程之间传递数据利用循环数组实现。

一种方式是:流解复用->视频+音频流->解码->YUV/PCM等->视音频编码->重新生成的音视频流->复用->流

/*

用opencv采集数据,并可以对数据进行图像处理,然后,我们可以用libx264库对视频进行编码成h264格式,然后进行推送至rtsp服务器。

源代码下载:

gotoinitError;

从一个对视频这块一无所知的码农,到现在稍稍入门的码农。没有什么大的变化,不过还是了解到行行都比较难搞。

FFMPEG转码的实现有多种方式:

FILE*pFile;

其实,之前想过多种方案。

另一种方式依赖AVFilter,这一部分在另外的几篇文章中解释怎么用。虽然AVFilter学习起来可能比较困难,但是在实际的编程应用中,依靠AVFilter做转码效率比第一种方式高,并且解码的CPU和时间消耗也少的多。所以,还是建议好好学习这部分的,毕竟我一直觉得FFMPEG的强项就是解码和转码。

pCodecCtx=pFormatCtx->streams[videoStream]->codec;

然后,live555这一端,用fifo(其实是管道)来搞,这样的好处在于 保证两个进程间通信。而且比较实时。

本例子是由FFEMPG的doc/example例子transcode.c修改而来,可以根据需求任意转换音视频的编码。

}elseif(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_AUDIO) {

Windows下利用live555实现H264实时流RTSP发送

http://blog.csdn.net/xiejiashu/article/details/8269873 用live555做本地视频采集转发,附源码

 

主要是重写getnextframe 代码

整个代码如下:

  1. #include "global.h"

  2. #include "FFmpegReadCamera.h"

  3. #include "H264LiveVideoServerMediaSubssion.hh"

  1. #include "H264FramedLiveSource.hh"

  2. #include "liveMedia.hh"

  3. #include "BasicUsageEnvironment.hh"

  4.  

  5. #define BUFSIZE 10000

  6.  

  7. DWORD WINAPI ChildFunc1(LPVOID);

  8. DWORD WINAPI ChildFunc2(LPVOID);

  9.  

  10.  

  11. static void announceStream(RTSPServer* rtspServer, ServerMediaSession* sms,char const* streamName)//显示RTSP连接信息

  12. {

  13.    char* url = rtspServer->rtspURL(sms);

  1.    UsageEnvironment& env = rtspServer->envir();

  2.    env <<streamName<< "n";

  3.    env << "Play this stream using the URL "" << url << ""n";

  1.    delete[] url;

  2. }

  3.  

  4. int main(int argc, char** argv)

  5. {

  6.    for (int i = 0; i < ARRAYLENGTH; ++i)

  1.    {

  2.       memset(&szbuffer[i],0,sizeof(StreamData));

  3.    }

  4.  

  5.    CreateThread(NULL,0,ChildFunc1,0,0,NULL);

  1.    Sleep(3000);

  2.    CreateThread(NULL,0,ChildFunc2,0,0,NULL);

  1.    while(1)

  2.    {

  3.       Sleep(1);

  4.    }

  5.     return 0;

  6.  

  7. }

  8.  

  9. DWORD WINAPI ChildFunc1(LPVOID p)

  1. {

  2.    int ret;

  3.    AVFormatContext *ofmt_ctx = NULL;

  1.    AVStream *out_stream;

  2.    AVStream *in_stream;

  3.    AVCodecContext *enc_ctx;

  4.    AVCodecContext *dec_ctx;

  5.    AVCodec* encoder;

  6.    enum AVMediaType type;

  7.    fp_write = fopen("test.h264","wb+");

  8.    unsigned int stream_index;

  9.    AVPacket enc_pkt;

  10.    int enc_got_frame;

  11.  

  12.    AVFormatContext *pFormatCtx;

  13.    int i, videoindex;

  14.    AVCodecContext *pCodecCtx;

  15.    AVCodec *pCodec;

  16.  

  17.    av_register_all();

  18.  

  19.    avformat_network_init();

  20.    pFormatCtx = avformat_alloc_context();

  21.  

  22.    avformat_alloc_output_context2(&ofmt_ctx,NULL,"h264",NULL);

  23.  

  24.    //Register Device 注册所有硬件

  25.    avdevice_register_all();

  26.    //Show Dshow Device 显示所有可用的硬件

  27.    show_dshow_device();

  28.    //Show Device Options 显示某一个硬件的所有参数(摄像头参数)

  29.    show_dshow_device_option();

  1.    //Show VFW Options

  2.    show_vfw_device();

  3.    //Windows

  4. #ifdef _WIN32

  5. #if USE_DSHOW

  6.    AVInputFormat *ifmt=av_find_input_format("dshow");

  7.    //Set own video device's name

  8.    if(avformat_open_input(&pFormatCtx,"video=Integrated Webcam",ifmt,NULL)!=0){

  9.       printf("Couldn't open input stream.(无法打开输入流)n");

  10.       return -1;

  11.    }

  12. #else

  1.    AVInputFormat *ifmt=av_find_input_format("vfwcap");

  2.    if(avformat_open_input(&pFormatCtx,"0",ifmt,NULL)!=0){

  3.       printf("Couldn't open input stream.(无法打开输入流)n");

  4.       return -1;

  5.    }

  6. #endif

  7. #endif

  8.    //Linux

  9. #ifdef linux

  10.    AVInputFormat *ifmt=av_find_input_format("video4linux2");

  11.    if(avformat_open_input(&pFormatCtx,"/dev/video0",ifmt,NULL)!=0){

  12.       printf("Couldn't open input stream.(无法打开输入流)n");

  13.       return -1;

  14.    }

  15. #endif

  16.  

  17.  

  18.    if(avformat_find_stream_info(pFormatCtx,NULL)<0)

  1.    {

  2.       printf("Couldn't find stream information.(无法获取流信息)n");

  3.       return -1;

  4.    }

  5.    videoindex=-1;

  6.    for(i=0; i<pFormatCtx->nb_streams; i++)

  7.       if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_VIDEO)

  1.       {

  2.          videoindex=i;

  3.          break;

  4.       }

  5.       if(videoindex==-1)

  6.       {

  7.          printf("Couldn't find a video stream.(没有找到视频流)n");

  8.          return -1;

  9.       }

  10.  

  11.       pCodecCtx=pFormatCtx->streams[videoindex]->codec;

  1.       pCodec=avcodec_find_decoder(pCodecCtx->codec_id);
  1.       if(pCodec==NULL)

  2.       {

  3.          printf("Codec not found.(没有找到解码器)n");

  4.          return -1;

  5.       }

  6.       if(avcodec_open2(pCodecCtx, pCodec,NULL)<0)

  7.       {

  8.          printf("Could not open codec.(无法打开解码器)n");

  9.          return -1;

  10.       }

  11.  

  12.       AVFrame *pFrame,*pFrameYUV;

  1.       pFrame=avcodec_alloc_frame();
  1.       pFrameYUV=avcodec_alloc_frame();
  1.       int length = avpicture_get_size(PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height);

  2.       uint8_t *out_buffer=(uint8_t *)av_malloc(length);

  3.  

  4.  

  5.       /*open output file*/

  6.       AVIOContext *avio_out = avio_alloc_context(out_buffer,length,0,NULL,NULL,write_buffer,NULL);

  1.       if (avio_out == NULL)

  2.       {

  3.          printf("申请内存失败! n");

  4.          return -1;

  5.       }

  6.  

  7.       ofmt_ctx->pb = avio_out;

  1.       ofmt_ctx->flags = AVFMT_FLAG_CUSTOM_IO;

  2.       for(int i = 0; i < 1; i++)

  3.       {

  4.          out_stream = avformat_new_stream(ofmt_ctx,NULL);

  5.          if (!out_stream)

  6.          {

  7.             av_log(NULL,AV_LOG_ERROR,"failed allocating output stream");

  1.             return AVERROR_UNKNOWN;

  2.          }

  3.          in_stream = pFormatCtx->streams[i];

  4.          dec_ctx = in_stream->codec;

  5.          enc_ctx = out_stream->codec;

  6.          //设置编码格式

  7.          if (dec_ctx->codec_type == AVMEDIA_TYPE_VIDEO)

  8.          {

  9.             encoder = avcodec_find_encoder(AV_CODEC_ID_H264);

  10.             enc_ctx->height = dec_ctx->height;

  11.             enc_ctx->width = dec_ctx->width;

  12.             enc_ctx->sample_aspect_ratio = dec_ctx->sample_aspect_ratio;

  13.             enc_ctx->pix_fmt = encoder->pix_fmts[0];

  14.             enc_ctx->time_base = dec_ctx->time_base;

  15.             enc_ctx->me_range = 16;

  16.             enc_ctx->max_qdiff = 4;

  17.             enc_ctx->qmin = 10;//10 这两个值调节清晰度

  18.             enc_ctx->qmax = 51;//51

  19.             enc_ctx->qcompress = 0.6;

  20.             enc_ctx->refs = 3;

  1.             enc_ctx->bit_rate = 500000;

  2.  

  3.             //enc_ctx->time_base.num = 1;

  1.             //enc_ctx->time_base.den = 25;
  1.             //enc_ctx->gop_size = 10;

  2.             //enc_ctx->bit_rate = 3000000;

  1.  

  2.             ret = avcodec_open2(enc_ctx,encoder,NULL);

  3.             if (ret < 0)

  4.             {

  5.                av_log(NULL,AV_LOG_ERROR,"Cannot open video encoder for stream #%un",i);

  6.                return ret;

  7.             }

  8.             //av_opt_set(enc_ctx->priv_data,"tune","zerolatency",0);

  1.          }

  2.          else if (dec_ctx->codec_type == AVMEDIA_TYPE_UNKNOWN)

  3.          {

  4.             av_log(NULL, AV_LOG_FATAL, "Elementary stream #%d is of unknown type, cannot proceedn", i);

  5.             return AVERROR_INVALIDDATA;

  6.          }

  7.          else

  8.          {

  9.             // if this stream must be remuxed

  10.             ret = avcodec_copy_context(ofmt_ctx->streams[i]->codec,pFormatCtx->streams[i]->codec);

  1.             if (ret < 0)

  2.             {

  3.                av_log(NULL, AV_LOG_ERROR, "Copying stream context failedn");

  4.                return ret;

  5.             }

  6.          }

  7.          if (ofmt_ctx->oformat->flags & AVFMT_GLOBALHEADER)

  8.          {

  9.             enc_ctx->flags |= CODEC_FLAG_GLOBAL_HEADER;

  10.          }

  11.       }

  12.       // init muxer, write output file header

  13.       ret = avformat_write_header(ofmt_ctx,NULL);

  14.       if (ret < 0)

  15.       {

  16.          if (ret < 0)

  17.          {

  18.             av_log(NULL, AV_LOG_ERROR, "Error occurred when opening output filen");

  19.             return ret;

  20.          }

  21.       }

  22.  

  23.       i = 0;

  24.       // pCodecCtx 解码的codec_context

  25.       avpicture_fill((AVPicture *)pFrameYUV, out_buffer, PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height);

  26.       //SDL----------------------------

  27.       if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER)) {

  28.          printf( "Could not initialize SDL - %sn", SDL_GetError());

  29.          return -1;

  30.       }

  31.       int screen_w=0,screen_h=0;

  32.       SDL_Surface *screen;

  33.       screen_w = pCodecCtx->width;

  1.       screen_h = pCodecCtx->height;
  1.       screen = SDL_SetVideoMode(screen_w, screen_h, 0,0);

  2.  

  3.       if(!screen) {

  4.          printf("SDL: could not set video mode - exiting:%sn",SDL_GetError());

  5.          return -1;

  6.       }

  7.       SDL_Overlay *bmp;

  8.       bmp = SDL_CreateYUVOverlay(pCodecCtx->width, pCodecCtx->height,SDL_YV12_OVERLAY, screen);

  9.       SDL_Rect rect;

  10.       //SDL End------------------------

  11.       int got_picture;

  12.  

  13.       AVPacket *packet=(AVPacket *)av_malloc(sizeof(AVPacket));

  1.       //Output Information-----------------------------

  2.       printf("File Information(文件信息)---------------------n");

  3.       av_dump_format(pFormatCtx,0,NULL,0);

  1.       printf("-------------------------------------------------n");
  1.  

  2. #if OUTPUT_YUV420P

  3.       FILE *fp_yuv=fopen("output.yuv","wb+");

  4. #endif

  5.  

  6.       struct SwsContext *img_convert_ctx;

  1.       img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height, PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL);

  2.       //------------------------------

  3.       //read all packets

  4.       while(av_read_frame(pFormatCtx, packet)>=0)

  5.       {

  6.          if(packet->stream_index==videoindex)

  1.          {

  2.  

  3.             type = pFormatCtx->streams[packet->stream_index]->codec->codec_type;

  1.             stream_index = packet->stream_index;

  2.             av_log(NULL, AV_LOG_DEBUG, "Demuxer gave frame of stream_index %un",stream_index);

  3.  

  4.             if (!pFrame)

  5.             {

  6.                ret = AVERROR(ENOMEM);

  1.                break;

  2.             }

  3.             packet->dts = av_rescale_q_rnd(packet->dts,

  4.                pFormatCtx->streams[stream_index]->time_base,

  1.                pFormatCtx->streams[stream_index]->codec->time_base,
  1.                (AVRounding)(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));
  1.             packet->pts = av_rescale_q_rnd(packet->pts,

  2.                pFormatCtx->streams[stream_index]->time_base,

  1.                pFormatCtx->streams[stream_index]->codec->time_base,
  1.                (AVRounding)(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));
  1.             ret = avcodec_decode_video2(pCodecCtx, pFrame, &got_picture, packet);
  1.             printf("Decode 1 Packettsize:%dtpts:%dn",packet->size,packet->pts);
  1.             if(ret < 0)

  2.             {

  3.                printf("Decode Error.(解码错误)n");

  4.                av_frame_free(&pFrame);

  1.                return -1;

  2.             }

  3.             if(got_picture)

  4.             {

  5.                //这句话是转换格式的函数,可用将rgb变为yuv格式

  1.                sws_scale(img_convert_ctx, (const uint8_t* const*)pFrame->data, pFrame->linesize, 0, pCodecCtx->height, pFrameYUV->data, pFrameYUV->linesize);

  2.                //下面对转换为YUV格式的AVFramer进行编码即可

  1.                pFrameYUV->width = pFrame->width;

  2.                pFrameYUV->height = pFrame->height;

  3.  

  4.                /*pFrameYUV->pts = av_frame_get_best_effort_timestamp(pFrameYUV);

  5.                pFrameYUV->pict_type = AV_PICTURE_TYPE_NONE;*/

  6.  

  7.                enc_pkt.data = NULL;

  1.                enc_pkt.size = 0;
  1.                av_init_packet(&enc_pkt);
  1.                enc_pkt.data = out_buffer;

  2.                enc_pkt.size = length;

  1.  

  2.                //编码必须是YUV420P格式,不然编码不会成功。

  1.                ret = avcodec_encode_video2(ofmt_ctx->streams[stream_index]->codec,&enc_pkt,pFrameYUV,&enc_got_frame);
  1.                printf("Encode 1 Packettsize:%dtpts:%dn",enc_pkt.size,enc_pkt.pts);
  1.                if (ret == 0) //一定要记得 ret 值为0 ,代表成功。-1 才是代表失败。

  2.                {

  3.                   fwrite(enc_pkt.data,enc_pkt.size,1,fp_write); //存储编码后的h264文件,可以作为测试用

  1.                   memcpy(szbuffer[recvcount].str,enc_pkt.data,enc_pkt.size);
  1.                   szbuffer[recvcount].len = enc_pkt.size;

  2.                   recvcount = (recvcount + 1)%ARRAYLENGTH;

  3.                }

  4.                if (ret < 0)

  5.                {

  6.                   printf("encode failed");

  7.                   return -1;

  8.                }

  9.                if (!enc_got_frame)

  10.                {

  11.                   continue;

  12.                }

  13.  

  14.                /* prepare packet for muxing */

  15.                enc_pkt.stream_index = stream_index;

  16.                enc_pkt.dts = av_rescale_q_rnd(enc_pkt.dts,

  17.                   ofmt_ctx->streams[stream_index]->codec->time_base,

  1.                   ofmt_ctx->streams[stream_index]->time_base,
  1.                   (AVRounding)(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));
  1.                enc_pkt.pts = av_rescale_q_rnd(enc_pkt.pts,

  2.                   ofmt_ctx->streams[stream_index]->codec->time_base,

  1.                   ofmt_ctx->streams[stream_index]->time_base,
  1.                   (AVRounding)(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));
  1.                enc_pkt.duration = av_rescale_q(enc_pkt.duration,

  2.                   ofmt_ctx->streams[stream_index]->codec->time_base,

  1.                   ofmt_ctx->streams[stream_index]->time_base);
  1.                av_log(NULL, AV_LOG_INFO, "Muxing frame %dn",i);

  2.                /* mux encoded frame */

  3.                av_write_frame(ofmt_ctx,&enc_pkt);

  1.                if (ret < 0)

  2.                {

  3.                   printf("encode failed");

  4.                   return -1;

  5.                }

  6.  

  7. #if OUTPUT_YUV420P

  8.                int y_size=pCodecCtx->width*pCodecCtx->height;

  9.                fwrite(pFrameYUV->data[0],1,y_size,fp_yuv); //Y

  10.                fwrite(pFrameYUV->data[1],1,y_size/4,fp_yuv); //U

  11.                fwrite(pFrameYUV->data[2],1,y_size/4,fp_yuv); //V

  12. #endif

  13.                SDL_LockYUVOverlay(bmp);

  1.                bmp->pixels[0]=pFrameYUV->data[0];
  1.                bmp->pixels[2]=pFrameYUV->data[1];
  1.                bmp->pixels[1]=pFrameYUV->data[2];
  1.                bmp->pitches[0]=pFrameYUV->linesize[0];
  1.                bmp->pitches[2]=pFrameYUV->linesize[1];
  1.                bmp->pitches[1]=pFrameYUV->linesize[2];
  1.                SDL_UnlockYUVOverlay(bmp);
  1.                rect.x = 0;

  2.                rect.y = 0;

  3.                rect.w = screen_w;

  1.                rect.h = screen_h;
  1.                SDL_DisplayYUVOverlay(bmp, &rect);

  2.                //Delay 40ms

  3.                SDL_Delay(40);

  4.             }

  5.          }

  6.          av_free_packet(packet);

  1.       }

  2.  

  3.       /* flush encoders */

  4.       for (i = 0; i < 1; i++) {

  5.          /* flush encoder */

  6.          ret = flush_encoder(ofmt_ctx,i);

  7.          if (ret < 0) {

  8.             av_log(NULL, AV_LOG_ERROR, "Flushing encoder failedn");

  9.             return -1;

  10.          }

  11.       }

  12.       av_write_trailer(ofmt_ctx);

  1.  

  2.       sws_freeContext(img_convert_ctx);

  1.  

  2. #if OUTPUT_YUV420P

  3.       fclose(fp_yuv);

  4. #endif

  5.  

  6.       SDL_Quit();

  7.  

  8.       av_free(out_buffer);

  9.       av_free(pFrameYUV);

  10.       avcodec_close(pCodecCtx);

  1.       avformat_close_input(&pFormatCtx);
  1.       //fcloseall();

  2.       return 0;

  3. }

  4.  

  5. DWORD WINAPI ChildFunc2(LPVOID p)

  1. {

  2.    //设置环境

  3.    UsageEnvironment* env;

  4.    Boolean reuseFirstSource = False;//如果为"true"则其他接入的客户端跟第一个客户端看到一样的视频流,否则其他客户端接入的时候将重新播放

  1.    TaskScheduler* scheduler = BasicTaskScheduler::createNew();

  2.    env = BasicUsageEnvironment::createNew(*scheduler);

  3.  

  4.    //创建RTSP服务器

  5.    UserAuthenticationDatabase* authDB = NULL;

  6.    RTSPServer* rtspServer = RTSPServer::createNew(*env, 8554, authDB);

  7.    if (rtspServer == NULL) {

  8.       *env << "Failed to create RTSP server: " << env->getResultMsg() << "n";

  9.       exit(1);

  10.    }

  11.    char const* descriptionString= "Session streamed by "testOnDemandRTSPServer"";

  12.  

  13.    //模拟实时流发送相关变量

  14.    int datasize;//数据区长度

  15.    unsigned char* databuf;//数据区指针

  16.    databuf = (unsigned char*)malloc(100000);

  17.    bool dosent;//rtsp发送标志位,为true则发送,否则退出

  1.  

  2.    //从文件中拷贝1M数据到内存中作为实时网络传输内存模拟,如果实时网络传输应该是双线程结构,记得在这里加上线程锁

  1.    //此外实时传输的数据拷贝应该是发生在H264FramedLiveSource文件中,所以这里只是自上往下的传指针过去给它
  1.     datasize = szbuffer[(recvcount+ARRAYLENGTH-1)%ARRAYLENGTH].len;

  2.    for (int i = 0; i < datasize; ++i)

  1.    {

  2.       databuf[i] = szbuffer[(recvcount+ARRAYLENGTH-1)%ARRAYLENGTH].str[i];

  3.    }

  4.    dosent = true;

  5.    //fclose(pf);

  6.  

  7.    //上面的部分除了模拟网络传输的部分外其他的基本跟live555提供的demo一样,而下面则修改为网络传输的形式,为此重写addSubsession的第一个参数相关文件

  1.    char const* streamName = "h264test";

  2.    ServerMediaSession* sms = ServerMediaSession::createNew(*env, streamName, streamName,descriptionString);

  3.    sms->addSubsession(H264LiveVideoServerMediaSubssion::createNew(*env, reuseFirstSource, &datasize, databuf,&dosent));//修改为自己实现的H264LiveVideoServerMediaSubssion

  1.    rtspServer->addServerMediaSession(sms);
  1.    announceStream(rtspServer, sms, streamName);//提示用户输入连接信息
  1.  

  2.    env->taskScheduler().doEventLoop(); //循环等待连接(没有链接的话,进不去下一步,无法调试)

  1.  

  2.    free(databuf);//释放掉内存

  3.    return 0;

  4. }

Source核心代码:

  1. void H264FramedLiveSource::doGetNextFrame()

  2. {

  3.    if (*Framed_dosent == true)

  4.    {

  5.  

  6.      bufsizel = szbuffer[(recvcount+ARRAYLENGTH-1)%ARRAYLENGTH].len;

  7.    if (bufsizel > fMaxSize)

  8.    {

  9.       fFrameSize = fMaxSize;

  10.    }

  11.    else

  1.    {

  2.       fFrameSize = bufsizel;

  3.    }

  4.        /* for (int i = 0; i < fFrameSize; ++i)

  5.       {

  6.          Framed_databuf[i] = szbuffer[(recvcount+ARRAYLENGTH-1)%ARRAYLENGTH].str[i];

  7.       } */

  8.      memcpy(fTo, szbuffer[(recvcount+ARRAYLENGTH-1)%ARRAYLENGTH].str, fFrameSize);

  1.    }

  2.    nextTask() = envir().taskScheduler().scheduleDelayedTask(0,(TaskFunc*)FramedSource::afterGetting, this);//表示延迟0秒后再执行 afterGetting 函数

  1.    return;

  2. }

代码下载链接:

C:UsersDELLDesktopffmpeg开发files 暂且在这,以后再改。

 

*/

如何实现:

 

score的值是一个宏定义AVPROBE_SCORE_RETRY,我们可以看一下它的定义:

最简单的基于FFmpeg的内存读写的例子:内存转码器

csdn工程:

primed=YES;

整体结构如下:

 

//注册编码器(其实编码器和解码器用的注册函数都是一样的:avcodec_register

 

原来的例子的作用更类似于remux,并没有实现转码的功能,只是实现了格式转换,比如ts转avi等。并不能实现音视频编码格式的转换,比如将h264转为mpeg2。

if(audioStream> -1) {

不过,这里的一个难点就是 libx264使用不太熟悉,导致后来我放弃了这种方案。

 print?

}

  • 采集并编码线程:

 

公司的一个项目二次开发要用到RTSP解码,对于我这个刚出道的彩笔工程师无疑是巨大的挑战。。网上教程不算多,但是也不算少。第一步编译ffmpeg 就卡了好久。。一个星期终于完工 下面我把代码贴出来吧 每个方法基本都有注释,有些是自己理解的,有些网上大神博客记载的 ,有错误的地方麻烦多见谅见谅,因为自己弄这个弄了很久,深知c是非人类语言=。=

最简单的基于FFmpeg的内存读写的例子:内存播放器

 

for(inti=0; inb_streams; i++) {

关键点分析:

[cpp] view plain copy

av_dict_set(&avdic,option_key2,option_value2,0);

 

NSLog(@"write image file: %@",fileName);

参考雷神的两篇日志

  1. <span style="font-family:SimHei;font-size:18px;">/* 
  2. * based on FFMPEG transcode.c 
  3. * modified by tongli 
  4. */  
  5. #include <stdio.h>  
  6. #include "snprintf.h"  
  7. extern "C"  
  8. {  
  9. #include <libavcodec/avcodec.h>  
  10. #include <libavformat/avformat.h>  
  11. #include <libavfilter/avfiltergraph.h>  
  12. #include <libavfilter/avcodec.h>  
  13. #include <libavfilter/buffersink.h>  
  14. #include <libavfilter/buffersrc.h>  
  15. #include <libavutil/opt.h>  
  16. #include <libavutil/pixdesc.h>  
  17. }  
  18. static AVFormatContext *ifmt_ctx;  
  19. static AVFormatContext *ofmt_ctx;  
  20. typedef struct FilteringContext {  
  21.     AVFilterContext *buffersink_ctx;  
  22.     AVFilterContext *buffersrc_ctx;  
  23.     AVFilterGraph *filter_graph;  
  24. } FilteringContext;  
  25. static FilteringContext *filter_ctx;  
  26.   
  27. static int open_input_file(const char *filename)  
  28. {  
  29.     int ret;  
  30.     unsigned int i;  
  31.   
  32.     ifmt_ctx = NULL;  
  33.     if ((ret = avformat_open_input(&ifmt_ctx, filename, NULL, NULL)) < 0) {  
  34.         av_log(NULL, AV_LOG_ERROR, "Cannot open input filen");  
  35.         return ret;  
  36.     }  
  37.   
  38.     if ((ret = avformat_find_stream_info(ifmt_ctx, NULL)) < 0) {  
  39.         av_log(NULL, AV_LOG_ERROR, "Cannot find stream informationn");  
  40.         return ret;  
  41.     }  
  42.   
  43.     for (i = 0; i < ifmt_ctx->nb_streams; i++) {  
  44.         AVStream *stream;  
  45.         AVCodecContext *codec_ctx;  
  46.         stream = ifmt_ctx->streams[i];  
  47.         codec_ctx = stream->codec;  
  48.         /* Reencode video & audio and remux subtitles etc. */  
  49.         if (codec_ctx->codec_type == AVMEDIA_TYPE_VIDEO  
  50.             || codec_ctx->codec_type == AVMEDIA_TYPE_AUDIO) {  
  51.             /* Open decoder */  
  52.             ret = avcodec_open2(codec_ctx,  
  53.                 avcodec_find_decoder(codec_ctx->codec_id), NULL);  
  54.             if (ret < 0) {  
  55.                 av_log(NULL, AV_LOG_ERROR, "Failed to open decoder for stream #%un", i);  
  56.                 return ret;  
  57.             }  
  58.         }  
  59.     }  
  60.   
  61.     av_dump_format(ifmt_ctx, 0, filename, 0);  
  62.     return 0;  
  63. }  
  64.   
  65. static int open_output_file(const char *filename)  
  66. {  
  67.     AVStream *out_stream;  
  68.     AVStream *in_stream;  
  69.     AVCodecContext *dec_ctx, *enc_ctx;  
  70.     AVCodec *encoder;  
  71.     int ret;  
  72.     unsigned int i;  
  73.   
  74.     ofmt_ctx = NULL;  
  75.     avformat_alloc_output_context2(&ofmt_ctx, NULL, NULL, filename);  
  76.     if (!ofmt_ctx) {  
  77.         av_log(NULL, AV_LOG_ERROR, "Could not create output contextn");  
  78.         return AVERROR_UNKNOWN;  
  79.     }  
  80.   
  81.     for (i = 0; i < ifmt_ctx->nb_streams; i++) {  
  82.         out_stream = avformat_new_stream(ofmt_ctx, NULL);  
  83.         if (!out_stream) {  
  84.             av_log(NULL, AV_LOG_ERROR, "Failed allocating output streamn");  
  85.             return AVERROR_UNKNOWN;  
  86.         }  
  87.   
  88.         in_stream = ifmt_ctx->streams[i];  
  89.         dec_ctx = in_stream->codec;  
  90.         enc_ctx = out_stream->codec;  
  91.   
  92.         if (dec_ctx->codec_type == AVMEDIA_TYPE_VIDEO)   
  93.         {  
  94.             encoder = avcodec_find_encoder(AV_CODEC_ID_H264);  
  95.             if (!encoder) {  
  96.                 av_log(NULL, AV_LOG_FATAL, "Neccessary encoder not foundn");  
  97.                 return AVERROR_INVALIDDATA;  
  98.             }  
  99.   
  100.             enc_ctx->height = dec_ctx->height;  
  101.             enc_ctx->width = dec_ctx->width;  
  102.             enc_ctx->sample_aspect_ratio = dec_ctx->sample_aspect_ratio;  
  103.                   
  104.             enc_ctx->pix_fmt = encoder->pix_fmts[0];  
  105.                   
  106.             enc_ctx->time_base = dec_ctx->time_base;  
  107.   
  108.             enc_ctx->me_range = 16;  
  109.             enc_ctx->max_qdiff = 4;  
  110.             enc_ctx->qmin = 10;  
  111.             enc_ctx->qmax = 51;  
  112.             enc_ctx->qcompress = 0.6;  
  113.             enc_ctx->refs = 3;  
  114.             enc_ctx->bit_rate = 500000;  
  115.               
  116.             ret = avcodec_open2(enc_ctx, encoder, NULL);  
  117.             if (ret < 0) {  
  118.                 av_log(NULL, AV_LOG_ERROR, "Cannot open video encoder for stream #%un", i);  
  119.                 return ret;  
  120.             }  
  121.         }  
  122.         else if (dec_ctx->codec_type == AVMEDIA_TYPE_UNKNOWN) {  
  123.             av_log(NULL, AV_LOG_FATAL, "Elementary stream #%d is of unknown type, cannot proceedn", i);  
  124.             return AVERROR_INVALIDDATA;  
  125.         }  
  126.         else if (dec_ctx->codec_type == AVMEDIA_TYPE_AUDIO)  
  127.         {  
  128.             encoder = avcodec_find_encoder(AV_CODEC_ID_PCM_ALAW);  
  129.             enc_ctx->sample_rate = dec_ctx->sample_rate;  
  130.             enc_ctx->channel_layout = dec_ctx->channel_layout;  
  131.             enc_ctx->channels = av_get_channel_layout_nb_channels(enc_ctx->channel_layout);  
  132.             enc_ctx->sample_fmt = encoder->sample_fmts[0];  
  133.             AVRational ar = { 1, enc_ctx->sample_rate };  
  134.             enc_ctx->time_base = ar;  
  135.   
  136.             ret = avcodec_open2(enc_ctx, encoder, NULL);  
  137.             if (ret < 0) {  
  138.                 av_log(NULL, AV_LOG_ERROR, "Cannot open video encoder for stream #%un", i);  
  139.                 return ret;  
  140.             }  
  141.         }  
  142.         else {  
  143.             ret = avcodec_copy_context(ofmt_ctx->streams[i]->codec,  
  144.                 ifmt_ctx->streams[i]->codec);  
  145.             if (ret < 0) {  
  146.                 av_log(NULL, AV_LOG_ERROR, "Copying stream context failedn");  
  147.                 return ret;  
  148.             }  
  149.         }  
  150.   
  151.         if (ofmt_ctx->oformat->flags & AVFMT_GLOBALHEADER)  
  152.             enc_ctx->flags |= CODEC_FLAG_GLOBAL_HEADER;  
  153.   
  154.     }  
  155.     av_dump_format(ofmt_ctx, 0, filename, 1);  
  156.   
  157.     if (!(ofmt_ctx->oformat->flags & AVFMT_NOFILE)) {  
  158.         ret = avio_open(&ofmt_ctx->pb, filename, AVIO_FLAG_WRITE);  
  159.         if (ret < 0) {  
  160.             av_log(NULL, AV_LOG_ERROR, "Could not open output file '%s'", filename);  
  161.             return ret;  
  162.         }  
  163.     }  
  164.   
  165.     /* init muxer, write output file header */  
  166.     ret = avformat_write_header(ofmt_ctx, NULL);  
  167.     if (ret < 0) {  
  168.         av_log(NULL, AV_LOG_ERROR, "Error occurred when opening output filen");  
  169.         return ret;  
  170.     }  
  171.   
  172.     return 0;  
  173. }  
  174.   
  175. static int init_filter(FilteringContext* fctx, AVCodecContext *dec_ctx,  
  176.     AVCodecContext *enc_ctx, const char *filter_spec)  
  177. {  
  178.     char args[512];  
  179.     int ret = 0;  
  180.     AVFilter *buffersrc = NULL;  
  181.     AVFilter *buffersink = NULL;  
  182.     AVFilterContext *buffersrc_ctx = NULL;  
  183.     AVFilterContext *buffersink_ctx = NULL;  
  184.     AVFilterInOut *outputs = avfilter_inout_alloc();  
  185.     AVFilterInOut *inputs = avfilter_inout_alloc();  
  186.     AVFilterGraph *filter_graph = avfilter_graph_alloc();  
  187.   
  188.     if (!outputs || !inputs || !filter_graph) {  
  189.         ret = AVERROR(ENOMEM);  
  190.         goto end;  
  191.     }  
  192.   
  193.     if (dec_ctx->codec_type == AVMEDIA_TYPE_VIDEO) {  
  194.         buffersrc = avfilter_get_by_name("buffer");  
  195.         buffersink = avfilter_get_by_name("buffersink");  
  196.         if (!buffersrc || !buffersink) {  
  197.             av_log(NULL, AV_LOG_ERROR, "filtering source or sink element not foundn");  
  198.             ret = AVERROR_UNKNOWN;  
  199.             goto end;  
  200.         }  
  201.   
  202.         snprintf(args, sizeof(args),  
  203.             "video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=%d/%d",  
  204.             dec_ctx->width, dec_ctx->height, dec_ctx->pix_fmt,  
  205.             dec_ctx->time_base.num, dec_ctx->time_base.den,  
  206.             dec_ctx->sample_aspect_ratio.num,  
  207.             dec_ctx->sample_aspect_ratio.den);  
  208.   
  209.         ret = avfilter_graph_create_filter(&buffersrc_ctx, buffersrc, "in",  
  210.             args, NULL, filter_graph);  
  211.         if (ret < 0) {  
  212.             av_log(NULL, AV_LOG_ERROR, "Cannot create buffer sourcen");  
  213.             goto end;  
  214.         }  
  215.   
  216.         ret = avfilter_graph_create_filter(&buffersink_ctx, buffersink, "out",  
  217.             NULL, NULL, filter_graph);  
  218.         if (ret < 0) {  
  219.             av_log(NULL, AV_LOG_ERROR, "Cannot create buffer sinkn");  
  220.             goto end;  
  221.         }  
  222.   
  223.         ret = av_opt_set_bin(buffersink_ctx, "pix_fmts",  
  224.             (uint8_t*)&enc_ctx->pix_fmt, sizeof(enc_ctx->pix_fmt),  
  225.             AV_OPT_SEARCH_CHILDREN);  
  226.         if (ret < 0) {  
  227.             av_log(NULL, AV_LOG_ERROR, "Cannot set output pixel formatn");  
  228.             goto end;  
  229.         }  
  230.     }  
  231.     else if (dec_ctx->codec_type == AVMEDIA_TYPE_AUDIO) {  
  232.         buffersrc = avfilter_get_by_name("abuffer");  
  233.         buffersink = avfilter_get_by_name("abuffersink");  
  234.         if (!buffersrc || !buffersink) {  
  235.             av_log(NULL, AV_LOG_ERROR, "filtering source or sink element not foundn");  
  236.             ret = AVERROR_UNKNOWN;  
  237.             goto end;  
  238.         }  
  239.   
  240.         if (!dec_ctx->channel_layout)  
  241.             dec_ctx->channel_layout =  
  242.             av_get_default_channel_layout(dec_ctx->channels);  
  243.         snprintf(args, sizeof(args),  
  244.             "time_base=%d/%d:sample_rate=%d:sample_fmt=%s:channel_layout=0x%"PRIx64,  
  245.             dec_ctx->time_base.num, dec_ctx->time_base.den, dec_ctx->sample_rate,  
  246.             av_get_sample_fmt_name(dec_ctx->sample_fmt),  
  247.             dec_ctx->channel_layout);  
  248.         ret = avfilter_graph_create_filter(&buffersrc_ctx, buffersrc, "in",  
  249.             args, NULL, filter_graph);  
  250.         if (ret < 0) {  
  251.             av_log(NULL, AV_LOG_ERROR, "Cannot create audio buffer sourcen");  
  252.             goto end;  
  253.         }  
  254.   
  255.         ret = avfilter_graph_create_filter(&buffersink_ctx, buffersink, "out",  
  256.             NULL, NULL, filter_graph);  
  257.         if (ret < 0) {  
  258.             av_log(NULL, AV_LOG_ERROR, "Cannot create audio buffer sinkn");  
  259.             goto end;  
  260.         }  
  261.   
  262.         ret = av_opt_set_bin(buffersink_ctx, "sample_fmts",  
  263.             (uint8_t*)&enc_ctx->sample_fmt, sizeof(enc_ctx->sample_fmt),  
  264.             AV_OPT_SEARCH_CHILDREN);  
  265.         if (ret < 0) {  
  266.             av_log(NULL, AV_LOG_ERROR, "Cannot set output sample formatn");  
  267.             goto end;  
  268.         }  
  269.   
  270.         ret = av_opt_set_bin(buffersink_ctx, "channel_layouts",  
  271.             (uint8_t*)&enc_ctx->channel_layout,  
  272.             sizeof(enc_ctx->channel_layout), AV_OPT_SEARCH_CHILDREN);  
  273.         if (ret < 0) {  
  274.             av_log(NULL, AV_LOG_ERROR, "Cannot set output channel layoutn");  
  275.             goto end;  
  276.         }  
  277.   
  278.         ret = av_opt_set_bin(buffersink_ctx, "sample_rates",  
  279.             (uint8_t*)&enc_ctx->sample_rate, sizeof(enc_ctx->sample_rate),  
  280.             AV_OPT_SEARCH_CHILDREN);  
  281.         if (ret < 0) {  
  282.             av_log(NULL, AV_LOG_ERROR, "Cannot set output sample raten");  
  283.             goto end;  
  284.         }  
  285.     }  
  286.     else {  
  287.         ret = AVERROR_UNKNOWN;  
  288.         goto end;  
  289.     }  
  290.   
  291.     /* Endpoints for the filter graph. */  
  292.     outputs->name = av_strdup("in");  
  293.     outputs->filter_ctx = buffersrc_ctx;  
  294.     outputs->pad_idx = 0;  
  295.     outputs->next = NULL;  
  296.   
  297.     inputs->name = av_strdup("out");  
  298.     inputs->filter_ctx = buffersink_ctx;  
  299.     inputs->pad_idx = 0;  
  300.     inputs->next = NULL;  
  301.   
  302.     if (!outputs->name || !inputs->name) {  
  303.         ret = AVERROR(ENOMEM);  
  304.         goto end;  
  305.     }  
  306.   
  307.     if ((ret = avfilter_graph_parse_ptr(filter_graph, filter_spec,  
  308.         &inputs, &outputs, NULL)) < 0)  
  309.         goto end;  
  310.   
  311.     if ((ret = avfilter_graph_config(filter_graph, NULL)) < 0)  
  312.         goto end;  
  313.   
  314.     /* Fill FilteringContext */  
  315.     fctx->buffersrc_ctx = buffersrc_ctx;  
  316.     fctx->buffersink_ctx = buffersink_ctx;  
  317.     fctx->filter_graph = filter_graph;  
  318.   
  319. end:  
  320.     avfilter_inout_free(&inputs);  
  321.     avfilter_inout_free(&outputs);  
  322.   
  323.     return ret;  
  324. }  
  325.   
  326. static int init_filters(void)  
  327. {  
  328.     const char *filter_spec;  
  329.     unsigned int i;  
  330.     int ret;  
  331.     filter_ctx = (FilteringContext*)av_malloc_array(ifmt_ctx->nb_streams, sizeof(*filter_ctx));  
  332.     if (!filter_ctx)  
  333.         return AVERROR(ENOMEM);  
  334.   
  335.     for (i = 0; i < ifmt_ctx->nb_streams; i++) {  
  336.         filter_ctx[i].buffersrc_ctx = NULL;  
  337.         filter_ctx[i].buffersink_ctx = NULL;  
  338.         filter_ctx[i].filter_graph = NULL;  
  339.         if (!(ifmt_ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO  
  340.             || ifmt_ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO))  
  341.             continue;  
  342.   
  343.   
  344.         if (ifmt_ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)  
  345.             filter_spec = "null"; /* passthrough (dummy) filter for video */  
  346.         else  
  347.             filter_spec = "anull"; /* passthrough (dummy) filter for audio */  
  348.         ret = init_filter(&filter_ctx[i], ifmt_ctx->streams[i]->codec,  
  349.             ofmt_ctx->streams[i]->codec, filter_spec);  
  350.         if (ret)  
  351.             return ret;  
  352.     }  
  353.     return 0;  
  354. }  
  355.   
  356. static int encode_write_frame(AVFrame *filt_frame, unsigned int stream_index, int *got_frame) {  
  357.     int ret;  
  358.     int got_frame_local;  
  359.     AVPacket enc_pkt;  
  360.     int(*enc_func)(AVCodecContext *, AVPacket *, const AVFrame *, int *) =  
  361.         (ifmt_ctx->streams[stream_index]->codec->codec_type ==  
  362.         AVMEDIA_TYPE_VIDEO) ? avcodec_encode_video2 : avcodec_encode_audio2;  
  363.   
  364.     if (!got_frame)  
  365.         got_frame = &got_frame_local;  
  366.   
  367.     av_log(NULL, AV_LOG_INFO, "Encoding framen");  
  368.     /* encode filtered frame */  
  369.     enc_pkt.data = NULL;  
  370.     enc_pkt.size = 0;  
  371.     av_init_packet(&enc_pkt);  
  372.     ret = enc_func(ofmt_ctx->streams[stream_index]->codec, &enc_pkt,  
  373.         filt_frame, got_frame);  
  374.     av_frame_free(&filt_frame);  
  375.     if (ret < 0)  
  376.         return ret;  
  377.     if (!(*got_frame))  
  378.         return 0;  
  379.   
  380.     /* prepare packet for muxing */  
  381.     enc_pkt.stream_index = stream_index;  
  382.     av_packet_rescale_ts(&enc_pkt,  
  383.         ofmt_ctx->streams[stream_index]->codec->time_base,  
  384.         ofmt_ctx->streams[stream_index]->time_base);  
  385.   
  386.     av_log(NULL, AV_LOG_DEBUG, "Muxing framen");  
  387.     /* mux encoded frame */  
  388.     ret = av_interleaved_write_frame(ofmt_ctx, &enc_pkt);  
  389.     return ret;  
  390. }  
  391.   
  392. static int filter_encode_write_frame(AVFrame *frame, unsigned int stream_index)  
  393. {  
  394.     int ret;  
  395.     AVFrame *filt_frame;  
  396.   
  397.     av_log(NULL, AV_LOG_INFO, "Pushing decoded frame to filtersn");  
  398.     /* push the decoded frame into the filtergraph */  
  399.     ret = av_buffersrc_add_frame_flags(filter_ctx[stream_index].buffersrc_ctx,  
  400.         frame, 0);  
  401.     if (ret < 0) {  
  402.         av_log(NULL, AV_LOG_ERROR, "Error while feeding the filtergraphn");  
  403.         return ret;  
  404.     }  
  405.   
  406.     /* pull filtered frames from the filtergraph */  
  407.     while (1) {  
  408.         filt_frame = av_frame_alloc();  
  409.         if (!filt_frame) {  
  410.             ret = AVERROR(ENOMEM);  
  411.             break;  
  412.         }  
  413.         av_log(NULL, AV_LOG_INFO, "Pulling filtered frame from filtersn");  
  414.         ret = av_buffersink_get_frame(filter_ctx[stream_index].buffersink_ctx,  
  415.             filt_frame);  
  416.         if (ret < 0) {  
  417.             /* if no more frames for output - returns AVERROR(EAGAIN) 
  418.             * if flushed and no more frames for output - returns AVERROR_EOF 
  419.             * rewrite retcode to 0 to show it as normal procedure completion 
  420.             */  
  421.             if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)  
  422.                 ret = 0;  
  423.             av_frame_free(&filt_frame);  
  424.             break;  
  425.         }  
  426.   
  427.         filt_frame->pict_type = AV_PICTURE_TYPE_NONE;  
  428.         ret = encode_write_frame(filt_frame, stream_index, NULL);  
  429.         if (ret < 0)  
  430.             break;  
  431.     }  
  432.   
  433.     return ret;  
  434. 葡京网投哪个正规,}  
  435.   
  436. static int flush_encoder(unsigned int stream_index)  
  437. {  
  438.     int ret;  
  439.     int got_frame;  
  440.   
  441.     if (!(ofmt_ctx->streams[stream_index]->codec->codec->capabilities &  
  442.         CODEC_CAP_DELAY))  
  443.         return 0;  
  444.   
  445.     while (1) {  
  446.         av_log(NULL, AV_LOG_INFO, "Flushing stream #%u encodern", stream_index);  
  447.         ret = encode_write_frame(NULL, stream_index, &got_frame);  
  448.         if (ret < 0)  
  449.             break;  
  450.         if (!got_frame)  
  451.             return 0;  
  452.     }  
  453.     return ret;  
  454. }  
  455.   
  456. int main(int argc, char **argv)  
  457. {  
  458.     int ret;  
  459.     AVPacket packet; //= { .data = NULL, .size = 0 };  
  460.     packet.data = NULL;  
  461.     packet.size = 0;  
  462.     AVFrame *frame = NULL;  
  463.     enum AVMediaType type;  
  464.     unsigned int stream_index;  
  465.     unsigned int i;  
  466.     int got_frame;  
  467.     int(*dec_func)(AVCodecContext *, AVFrame *, int *, const AVPacket *);  
  468.   
  469.     av_register_all();  
  470.     avfilter_register_all();  
  471.   
  472.     if ((ret = open_input_file("test.ts")) < 0)  
  473.         goto end;  
  474.     if ((ret = open_output_file("test.avi")) < 0)  
  475.         goto end;  
  476.     if ((ret = init_filters()) < 0)  
  477.         goto end;  
  478.   
  479.     /* read all packets */  
  480.     while (1) {  
  481.         if ((ret = av_read_frame(ifmt_ctx, &packet)) < 0)  
  482.             break;  
  483.         stream_index = packet.stream_index;  
  484.         type = ifmt_ctx->streams[packet.stream_index]->codec->codec_type;  
  485.         av_log(NULL, AV_LOG_DEBUG, "Demuxer gave frame of stream_index %un",  
  486.             stream_index);  
  487.   
  488.         if (filter_ctx[stream_index].filter_graph) {  
  489.             av_log(NULL, AV_LOG_DEBUG, "Going to reencode&filter the framen");  
  490.             frame = av_frame_alloc();  
  491.             if (!frame) {  
  492.                 ret = AVERROR(ENOMEM);  
  493.                 break;  
  494.             }  
  495.             av_packet_rescale_ts(&packet,  
  496.                 ifmt_ctx->streams[stream_index]->time_base,  
  497.                 ifmt_ctx->streams[stream_index]->codec->time_base);  
  498.             dec_func = (type == AVMEDIA_TYPE_VIDEO) ? avcodec_decode_video2 :  
  499.                 avcodec_decode_audio4;  
  500.             ret = dec_func(ifmt_ctx->streams[stream_index]->codec, frame,  
  501.                 &got_frame, &packet);  
  502.             if (ret < 0) {  
  503.                 av_frame_free(&frame);  
  504.                 av_log(NULL, AV_LOG_ERROR, "Decoding failedn");  
  505.                 break;  
  506.             }  
  507.   
  508.             if (got_frame) {  
  509.                 frame->pts = av_frame_get_best_effort_timestamp(frame);  
  510.                 ret = filter_encode_write_frame(frame, stream_index);  
  511.                 av_frame_free(&frame);  
  512.                 if (ret < 0)  
  513.                     goto end;  
  514.             }  
  515.             else {  
  516.                 av_frame_free(&frame);  
  517.             }  
  518.         }  
  519.         else {  
  520.             /* remux this frame without reencoding */  
  521.             av_packet_rescale_ts(&packet,  
  522.                 ifmt_ctx->streams[stream_index]->time_base,  
  523.                 ofmt_ctx->streams[stream_index]->time_base);  
  524.   
  525.             ret = av_interleaved_write_frame(ofmt_ctx, &packet);  
  526.             if (ret < 0)  
  527.                 goto end;  
  528.         }  
  529.         av_free_packet(&packet);  
  530.     }  
  531.   
  532.     /* flush filters and encoders */  
  533.     for (i = 0; i < ifmt_ctx->nb_streams; i++) {  
  534.         /* flush filter */  
  535.         if (!filter_ctx[i].filter_graph)  
  536.             continue;  
  537.         ret = filter_encode_write_frame(NULL, i);  
  538.         if (ret < 0) {  
  539.             av_log(NULL, AV_LOG_ERROR, "Flushing filter failedn");  
  540.             goto end;  
  541.         }  
  542.   
  543.         /* flush encoder */  
  544.         ret = flush_encoder(i);  
  545.         if (ret < 0) {  
  546.             av_log(NULL, AV_LOG_ERROR, "Flushing encoder failedn");  
  547.             goto end;  
  548.         }  
  549.     }  
  550.   
  551.     av_write_trailer(ofmt_ctx);  
  552. end:  
  553.     av_free_packet(&packet);  
  554.     av_frame_free(&frame);  
  555.     for (i = 0; i < ifmt_ctx->nb_streams; i++) {  
  556.         avcodec_close(ifmt_ctx->streams[i]->codec);  
  557.         if (ofmt_ctx && ofmt_ctx->nb_streams > i && ofmt_ctx->streams[i] && ofmt_ctx->streams[i]->codec)  
  558.             avcodec_close(ofmt_ctx->streams[i]->codec);  
  559.         if (filter_ctx && filter_ctx[i].filter_graph)  
  560.             avfilter_graph_free(&filter_ctx[i].filter_graph);  
  561.     }  
  562. 葡京正网网投,    av_free(filter_ctx);  
  563.     avformat_close_input(&ifmt_ctx);  
  564.     if (ofmt_ctx && !(ofmt_ctx->oformat->flags & AVFMT_NOFILE))  
  565.         avio_closep(&ofmt_ctx->pb);  
  566.     avformat_free_context(ofmt_ctx);  
  567.   
  568.     if (ret < 0)  
  569.         av_log(NULL, AV_LOG_ERROR, "Error occurred: %sn"); //av_err2str(ret));  
  570.   
  571.     return ret ? 1 : 0;  
  572. }  
  573.   
  574. </span>  

NSString*fileName;

  • 将编码后的数据推送至rtsp264线程

本例子是视频mpeg2转h264,音频mpegaudio转g711。

intframeFinished=0;

下面一个个分析下实现思路:

 

return;

 

avpicture_free(&picture);

当然,在windows下,也可以通过进程间通信的方式来实现 有很多方式,这里面不多做介绍。

NSLog(@"fileName = %@",moviePath);

比较靠谱点的是在linux下,用fifo传输数据,一边采集并转化为h264,linux自己可以转,这个比windows简单多了。

}

 

- setupScaler

参考网上两个哥们的日志

ffplay -rtsp_transport tcp -max_delay 5000000rtsp://mms.cnr.cn/cnr003?MzE5MTg0IzEjIzI5NjgwOQ==

方案一:

//usesTcp外部传yes则添加参数

题目:视频流在Windows系统上的实时捕捉与传输 

fmt:强制指定AVFormatContext中AVInputFormat的。这个参数一般情况下可以设置为NULL,这样FFmpeg可以自动检测AVInputFormat。

参考资料:以下资料都是我从网上找到并积累的,感觉都还可以,有参考价值。

- seekTime:seconds{

葡京正网网投 3

[_audioController_startAudio];

方案二:

0,

}

但是,还有更简单的方式,我们完全可以用多线程来实现,在另一个线程中,我们利用循环数组的方式实现,这样的话,可以保证实时性。

}

后来,看到雷神写的一篇文章,终于让我下定决心,用ffmpeg+live555来搞。

#define AVPROBE_SCORE_MAX100 ///< maximum score

葡京正网网投 4

//外部可以手动设置视屏宽高

言归正传:开始讲讲 我的大致思路:如下图所示。

}

outputWidth,

avcodec_register_all();

/*

if(videoStream==-1&&audioStream==-1) {

1.保存YUV420P格式的数据

av_log(NULL,AV_LOG_ERROR,"Unsupported codec!n");

}

avformat_network_init();

//解码后的视频帧数据保存在pFrame变量中,然后经过swscale函数转换后,将视频帧数据保存在pFrameYUV变量中。最后将pFrameYUV中的数据写入成文件。AVFrame *pFrameYUV

// AVPacket packet;

fclose;

// Find the first video stream

//这里是保存在avpicture(AVPicture的结成:AVPicture结构体是AVFrame结构体的子集――AVFrame结构体的开始部分与AVPicture结构体是一样的)

AVDictionary*opts =0;

[audioPacketQueueLockunlock];

3.读取完整的一帧压缩编码的数据:read_frame_internal()

- stepFrame{

avformat_seek_file(pFormatCtx,videoStream, targetFrame, targetFrame, targetFrame,AVSEEK_FLAG_FRAME);

- savePPMPicture:(AVPicture)pict width:width height:height index:iFrame{

videoStream= i;

*/

file:打开的视音频流的URL。

NSLog(@"set up audiodecoder");

//函数为pFormatCtx->streams填充上正确的信息

此外还可以附加一些参数

pCodecCtx->height,

while(!frameFinished &&av_read_frame(pFormatCtx, &packet) >=0) {

在实际使用ffmpeg编程中,可以通过AVDictionary把参数传给avformat_open_input()

//打开解码器

picture.linesize);

fprintf(pFile,"P6n%d %dn255n", width, height);

if(avcodec_open2(pCodecCtx, pCodec,NULL) <0) {

//dump_format(pFormatCtx,0,argv[1],0);

gotoinitError;

注:av_read_frame()内部实际上就是调用的read_frame_internal()。

}

它其实已经实现了解码器的查找,解码器的打开,视音频帧的读取,视音频帧的解码等工作。换句话说,该函数实际上已经“走通”的解码的整个流程

//打开输入文件

if {

avformat_open_input(&pFormatCtx,url,NULL,&avdic);

AVRationaltimeBase =pFormatCtx->streams[videoStream]->time_base;

ffplayrtsp://mms.cnr.cn/cnr003?MzE5MTg0IzEjIzI5NjgwOQ==

//两种流都没找到返回错误

av_dict_set(&avdic,option_key,option_value,0);

av_register_all();

NSLog(@"WRITE?");

NSLog(@"found video stream");

fwrite(pFrameYUV->data[0],(pCodecCtx->width)*(pCodecCtx->height),1,output);

gotoinitError;

*/

// NSLog(@"audio stream");

}

}

if(emptyAudioBuffer) {

这些数据可以在后面通过av_free_packet()来释放。函数avcodec_decode_video()把包转换为帧。然而当解码一个包的时候,我们可能没有得到我们需要的关于帧的信息。因此,

//区分音频视屏及其他流(现在pFormatCtx->streams仅仅是一组大小为pFormatCtx->nb_streams的指针,所以让我们先跳过它直到我们找到一个视频流。)

av_log(NULL,AV_LOG_ERROR,"Couldn't find stream informationn");

avpicture_alloc(&picture,PIX_FMT_RGB24,outputWidth,outputHeight);

//取出包含在文件内的流信息

sws_scale(img_convert_ctx,

if(avformat_find_stream_info(pFormatCtx,NULL) <0) {//函数正常执行返回值是大于等于0的,这个函数只是检测文件的头部,所以接着我们需要检查在晚间中的流信息

inty;

ps:

dictionay:附加的一些选项参数,一般情况下可以设置为NULL。

initError:

pFrame=av_frame_alloc();

FFmpeg内部判断封装格式的原理实际上是对每种AVInputFormat给出一个分数,满分是100分,越有可能正确的AVInputFormat给出的分数就越高。最后选择分数最高的AVInputFormat作为推测结果。

/*

audioStream= i;

2.打开解码器:avcodec_open2()

ps:有些人可能会从旧的指导中记得有两个关于这些代码其它部分:添加CODEC_FLAG_TRUNCATED到pCodecCtx->flags和添加一个hack来粗糙的修正帧率。这两个修正已经不在存在于ffplay.c中。

}

audioPacketQueueSize+=packet.size;

}

//NSLog;

由此我们可以得出score取值是25,即如果推测后得到的最佳AVInputFormat的分值低于25,就认为没有找到合适的AVInputFormat。

audioStream=-1;

char option_value[]="tcp";

转化的代码:

ps:如果想将转换后的原始数据存成文件,只需要将pFrameYUV的data指针指向的数据写入文件就可以了。

ffplay -rtsp_transport tcprtsp://mms.cnr.cn/cnr003?MzE5MTg0IzEjIzI5NjgwOQ==

ps:函数调用成功之后处理过的AVFormatContext结构体。

av_log(NULL,AV_LOG_ERROR,"Couldn't open filen");

score变量是一个判决AVInputFormat的分数的门限值,如果最后得到的AVInputFormat的分数低于该门限值,就认为没有找到合适的AVInputFormat。

NSLog(@"error not find");

img_convert_ctx=sws_getContext(pCodecCtx->width,

outputWidth=pCodecCtx->width;

2.保存RGB24格式的数据

if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_VIDEO) {

picture.data,

//what?

self.outputHeight=pCodecCtx->height;

// Close file

char option_value2[]="5000000";

}

(constuint8_t*const*)pFrame->data,

sws_freeContext(img_convert_ctx);

//需要输出的格式可以修改

}

if(packet.stream_index==videoStream) {

- initWithVideo:(NSString*)moviePath usesTcp:usesTcp{

}

// Allocate RGB picture

NSLog(@"error not found stream");

av_log(NULL,AV_LOG_ERROR,"Cannot open video decodern");

[selfsetupAudioDecoder];

outputHeight,

//寻找解码器

//表示有音频输入

if(pFile ==NULL) {

其中AVPROBE_SCORE_MAX是score的最大值,取值是100:

NSLog(@"error not open");

char option_key2[]="max_delay";

}

NSLog(@"found audio stream");

// Decode video frame

当我们得到下一帧的时候,avcodec_decode_video()为我们设置了帧结束标志frameFinished

if(packet.stream_index==audioStream) {

我们使用分数的方式来表示帧率是因为很多编解码器使用非整数的帧率(例如NTSC使用29.97fps)

returnpacket.pts* timeBase.num/ timeBase.den;

NSLog(@"Stream");

// Release old picture and scaler

AVDictionary *avdic=NULL;

AVRationaltimeBase =pFormatCtx->streams[videoStream]->time_base;

for(y=0; y

// Is this a packet from the video stream?

returnframeFinished!=0;

//注册所有容器的格式和codec (能够自动选择相应的文件格式和编码器,只需要调用一次)

}

//流中关于编解码器的信息就是被我们叫做"codec context"的东西。这里面包含了流中所使用的关于编解码器的所有信息,现在我们有了一个指向他的指针。但是我们必需要找到真正的编解码器并且打开它

returnself;

gotoinitError;

if(avformat_open_input(&pFormatCtx, [moviePathUTF8String],NULL, &opts) !=0) {

avcodec_decode_video2(pCodecCtx,pFrame, &frameFinished, &packet);

3.保存UYVY格式的数据

}

- currentTime{

pCodecCtx->height,

fwrite(pFrameYUV->data[0],(pCodecCtx->width)*(pCodecCtx->height)*3,1,output);

if(!(self=[superinit]))returnnil;

/*

1.查找解码器:find_decoder()

av_dict_set(&opts,"rtsp_transport","tcp",0);

NSLog;

/*

fileName = [UtilitiesdocumentsPath:[NSStringstringWithFormat:@"image%04d.ppm",iFrame]];

}

if

gotoinitError;

pCodec =avcodec_find_decoder(pCodecCtx->codec_id);

4.解码一些压缩编码数据:try_decode_frame()

//sws_scale(img_convert_ctx, (const uint8_t* const*)pFrame->data, pFrame->linesize, 0, pCodecCtx->height, pFrameYUV->data, pFrameYUV->linesize);

fwrite(pFrameYUV->data[2],(pCodecCtx->width)*(pCodecCtx->height)/4,1,output);

pFrame->linesize,

// Open file

videoStream=-1;

av_read_frame()读取一个包并且把它保存到AVPacket结构体中。注意我们仅仅申请了一个包的结构体――ffmpeg为我们申请了内部的数据的内存并通过packet.data指针来指向它。

pFile =fopen([fileNamecStringUsingEncoding:NSASCIIStringEncoding],"wb");

pCodecCtx->pix_fmt,

avcodec_flush_buffers(pCodecCtx);

}

if(pCodec ==NULL) {

char url[]="rtsp://mms.cnr.cn/cnr003?MzE5MTg0IzEjIzI5NjgwOQ==";

}

源码链接 (如果百度云服务器太渣,留邮箱我发给你们) audioStream没有实现,因为目前的需求只是完成视频流的解析,有兴趣的朋友自己去完善吧,相信它会给刚刚接触到ffmpeg的朋友带来很大帮助

//对帧的操作?

PIX_FMT_RGB24,

returnnil;

- convertFrameToRGB{

ps:在打开一些流媒体的时候可能需要附加一些参数。

fwrite(pFrameYUV->data[0],(pCodecCtx->width)*(pCodecCtx->height),2,output);

//文件打开动作,然后写入RGB数据。我们一次向文件写入一行数据

staticintsws_flags =SWS_FAST_BILINEAR;

因此,我必需假设它们不再必要。我们移除了那些代码后还有一个需要指出的不同点:pCodecCtx->time_base现在已经保存了帧率的信息。time_base是一个结构体,它里面有一个分子和分母(AVRational)。

[_audioControllerenqueueBuffer:emptyAudioBuffer];

char option_key[]="rtsp_transport";

avformat_open_input(ps, url, fmt, dict);

sws_flags,NULL,NULL,NULL);

//打开流媒体的函数是avformat_open_input()其中打开网络流的话,前面要加上函数avformat_network_init()

#define AVPROBE_SCORE_RETRY (AVPROBE_SCORE_MAX/4)

*/

// Set the RTSP Options

}

int64_ttargetFrame = timeBase.den/ timeBase.num* seconds);

/*

}

如果直接进行打开是不会成功的:

这时候我们需要指定其传输方式为TCP

*/

{

// Write header

fwrite(pFrameYUV->data[1],(pCodecCtx->width)*(pCodecCtx->height)/4,1,output);

AVCodec*pCodec;

[audioPacketQueueLocklock];

//给视频帧分配空间以便存储解码后的图片

*/

fwrite(pict.data[0]+y*pict.linesize[0],1, width*3, pFile);

// S转化(PIX_FMT_UYVY422PIX_FMT_YUV422PPIX_FMT_RGB24)

[audioPacketQueueaddObject:[NSMutableDatadataWithBytes:&packetlength:sizeof]];

本文由葡京网投哪个正规发布于首页,转载请注明出处:iOS使用ffmpeg播放rstp实时监控视频数据流,搞了一周葡京网投哪个正规:

关键词:

上一篇:没有了

下一篇:微软发布Windows,安装指南