/*** * 张晖 Hui Zhang* zhanghuicuc@gmail.com* 中国传媒大学/数字电视技术* Communication University of China / Digital TV Technology* * 本程序实现了读取PC端摄像头数据并进行编码和流媒体传输。**/#include <stdio.h>
#include <windows.h>
extern "C"
{
#include "libavutil\opt.h"
#include "libavcodec\avcodec.h"
#include "libavformat\avformat.h"
#include "libavutil\time.h"
#include "libavdevice\avdevice.h"
#include "libswscale/swscale.h"
#include "libavutil/mathematics.h"
};//Show Device
void show_dshow_device(){AVFormatContext *pFmtCtx = avformat_alloc_context();AVDictionary* options = NULL;av_dict_set(&options, "list_devices", "true", 0);AVInputFormat *iformat = av_find_input_format("dshow");printf("Device Info=============\n");avformat_open_input(&pFmtCtx, "video=dummy", iformat, &options);printf("========================\n");
}int flush_encoder(AVFormatContext *ifmt_ctx,AVFormatContext *ofmt_ctx, unsigned int stream_index, int framecnt);int exit_thread = 0;
DWORD WINAPI MyThreadFunction(LPVOID lpParam)
{while ((getchar()) != '\n');exit_thread = 1;return 0;
}int main(int argc, char* argv[])
{AVFormatContext *ifmt_ctx=NULL;AVFormatContext *ofmt_ctx;AVInputFormat* ifmt;AVStream* video_st;AVCodecContext* pCodecCtx;AVCodec* pCodec;AVPacket *dec_pkt, enc_pkt;AVFrame *pframe, *pFrameYUV;struct SwsContext *img_convert_ctx;char capture_name[80] = {0};char device_name[80] = {0};int framecnt=0;int videoindex;int i;int ret;HANDLE  hThread;const char* out_path = "rtmp://localhost/live/livestream";    int dec_got_frame,enc_got_frame;av_register_all();//Register Deviceavdevice_register_all();avformat_network_init();//Show Dshow Device  show_dshow_device();printf("\nChoose capture device: ");if (gets(capture_name) == 0){printf("Error in gets()\n");return -1;}sprintf(device_name, "video=USB2.0 Camera");//sprintf(device_name, "video=screen-capture-recorder");ifmt=av_find_input_format("dshow");//Set own video device's nameif (avformat_open_input(&ifmt_ctx, device_name, ifmt, NULL) != 0){printf("Couldn't open input stream.(无法打开输入流)\n");return -1;}//input initializeif (avformat_find_stream_info(ifmt_ctx, NULL)<0){printf("Couldn't find stream information.(无法获取流信息)\n");return -1;}videoindex = -1;for (i = 0; i<ifmt_ctx->nb_streams; i++)if (ifmt_ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO){videoindex = i;break;}if (videoindex == -1){printf("Couldn't find a video stream.(没有找到视频流)\n");return -1;}if (avcodec_open2(ifmt_ctx->streams[videoindex]->codec, avcodec_find_decoder(ifmt_ctx->streams[videoindex]->codec->codec_id), NULL)<0){printf("Could not open codec.(无法打开解码器)\n");return -1;}//output initializeavformat_alloc_output_context2(&ofmt_ctx, NULL, "flv", out_path);//output encoder initializepCodec = avcodec_find_encoder(AV_CODEC_ID_H264);if (!pCodec){printf("Can not find encoder! (没有找到合适的编码器!)\n");return -1;}pCodecCtx=avcodec_alloc_context3(pCodec);pCodecCtx->pix_fmt = PIX_FMT_YUV420P;pCodecCtx->width = ifmt_ctx->streams[videoindex]->codec->width;pCodecCtx->height = ifmt_ctx->streams[videoindex]->codec->height;pCodecCtx->time_base.num = 1;pCodecCtx->time_base.den = 25;pCodecCtx->bit_rate = 400000;pCodecCtx->gop_size = 250;/* Some formats want stream headers to be separate. */if (ofmt_ctx->oformat->flags & AVFMT_GLOBALHEADER)pCodecCtx->flags |= CODEC_FLAG_GLOBAL_HEADER;//H264 codec param//pCodecCtx->me_range = 16;//pCodecCtx->max_qdiff = 4;//pCodecCtx->qcompress = 0.6;pCodecCtx->qmin = 10;pCodecCtx->qmax = 51;//Optional ParampCodecCtx->max_b_frames = 3;// Set H264 preset and tuneAVDictionary *param = 0;av_dict_set(¶m, "preset", "fast", 0);av_dict_set(¶m, "tune", "zerolatency", 0);if (avcodec_open2(pCodecCtx, pCodec,¶m) < 0){printf("Failed to open encoder! (编码器打开失败!)\n");return -1;}//Add a new stream to output,should be called by the user before avformat_write_header() for muxingvideo_st = avformat_new_stream(ofmt_ctx, pCodec);if (video_st == NULL){return -1;}video_st->time_base.num = 1;video_st->time_base.den = 25;video_st->codec = pCodecCtx;//Open output URL,set before avformat_write_header() for muxingif (avio_open(&ofmt_ctx->pb,out_path, AVIO_FLAG_READ_WRITE) < 0){printf("Failed to open output file! (输出文件打开失败!)\n");return -1;}//Show some Informationav_dump_format(ofmt_ctx, 0, out_path, 1);//Write File Headeravformat_write_header(ofmt_ctx,NULL);//prepare before decode and encodedec_pkt = (AVPacket *)av_malloc(sizeof(AVPacket));//enc_pkt = (AVPacket *)av_malloc(sizeof(AVPacket));//camera data has a pix fmt of RGB,convert it to YUV420img_convert_ctx = sws_getContext(ifmt_ctx->streams[videoindex]->codec->width, ifmt_ctx->streams[videoindex]->codec->height, ifmt_ctx->streams[videoindex]->codec->pix_fmt, pCodecCtx->width, pCodecCtx->height, PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL);pFrameYUV = av_frame_alloc();uint8_t *out_buffer = (uint8_t *)av_malloc(avpicture_get_size(PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height));avpicture_fill((AVPicture *)pFrameYUV, out_buffer, PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height);printf("\n --------call started----------\n\n");printf("Press enter to stop...");hThread = CreateThread(NULL,                   // default security attributes0,                      // use default stack size  MyThreadFunction,       // thread function nameNULL,          // argument to thread function 0,                      // use default creation flags NULL);   // returns the thread identifier //start decode and encodeint64_t start_time=av_gettime();while (av_read_frame(ifmt_ctx, dec_pkt) >= 0){ if (exit_thread)break;av_log(NULL, AV_LOG_DEBUG, "Going to reencode the frame\n");pframe = av_frame_alloc();if (!pframe) {ret = AVERROR(ENOMEM);return -1;}//av_packet_rescale_ts(dec_pkt, ifmt_ctx->streams[dec_pkt->stream_index]->time_base,//  ifmt_ctx->streams[dec_pkt->stream_index]->codec->time_base);ret = avcodec_decode_video2(ifmt_ctx->streams[dec_pkt->stream_index]->codec, pframe,&dec_got_frame, dec_pkt);if (ret < 0) {av_frame_free(&pframe);av_log(NULL, AV_LOG_ERROR, "Decoding failed\n");break;}if (dec_got_frame){sws_scale(img_convert_ctx, (const uint8_t* const*)pframe->data, pframe->linesize, 0, pCodecCtx->height, pFrameYUV->data, pFrameYUV->linesize);    enc_pkt.data = NULL;enc_pkt.size = 0;av_init_packet(&enc_pkt);ret = avcodec_encode_video2(pCodecCtx, &enc_pkt, pFrameYUV, &enc_got_frame);av_frame_free(&pframe);if (enc_got_frame == 1){//printf("Succeed to encode frame: %5d\tsize:%5d\n", framecnt, enc_pkt.size);framecnt++;  enc_pkt.stream_index = video_st->index;//Write PTSAVRational time_base = ofmt_ctx->streams[videoindex]->time_base;//{ 1, 1000 };AVRational r_framerate1 = ifmt_ctx->streams[videoindex]->r_frame_rate;// { 50, 2 };AVRational time_base_q = { 1, AV_TIME_BASE };//Duration between 2 frames (us)int64_t calc_duration = (double)(AV_TIME_BASE)*(1 / av_q2d(r_framerate1));  //内部时间戳//Parameters//enc_pkt.pts = (double)(framecnt*calc_duration)*(double)(av_q2d(time_base_q)) / (double)(av_q2d(time_base));enc_pkt.pts = av_rescale_q(framecnt*calc_duration, time_base_q, time_base);enc_pkt.dts = enc_pkt.pts;enc_pkt.duration = av_rescale_q(calc_duration, time_base_q, time_base); //(double)(calc_duration)*(double)(av_q2d(time_base_q)) / (double)(av_q2d(time_base));enc_pkt.pos = -1;//Delayint64_t pts_time = av_rescale_q(enc_pkt.dts, time_base, time_base_q);int64_t now_time = av_gettime() - start_time;if (pts_time > now_time)av_usleep(pts_time - now_time);ret = av_interleaved_write_frame(ofmt_ctx, &enc_pkt);av_free_packet(&enc_pkt);}}else {av_frame_free(&pframe);}av_free_packet(dec_pkt);}//Flush Encoderret = flush_encoder(ifmt_ctx,ofmt_ctx,0,framecnt);if (ret < 0) {printf("Flushing encoder failed\n");return -1;}//Write file trailerav_write_trailer(ofmt_ctx);//Cleanif (video_st)avcodec_close(video_st->codec);av_free(out_buffer);avio_close(ofmt_ctx->pb);avformat_free_context(ifmt_ctx);avformat_free_context(ofmt_ctx);CloseHandle(hThread);return 0;
}int flush_encoder(AVFormatContext *ifmt_ctx, AVFormatContext *ofmt_ctx, unsigned int stream_index, int framecnt){int ret;int got_frame;AVPacket enc_pkt;if (!(ofmt_ctx->streams[stream_index]->codec->codec->capabilities &CODEC_CAP_DELAY))return 0;while (1) {enc_pkt.data = NULL;enc_pkt.size = 0;av_init_packet(&enc_pkt);ret = avcodec_encode_video2 (ofmt_ctx->streams[stream_index]->codec, &enc_pkt,NULL, &got_frame);av_frame_free(NULL);if (ret < 0)break;if (!got_frame){ret=0;break;}printf("Flush Encoder: Succeed to encode 1 frame!\tsize:%5d\n",enc_pkt.size);//Write PTSAVRational time_base = ofmt_ctx->streams[stream_index]->time_base;//{ 1, 1000 };AVRational r_framerate1 = ifmt_ctx->streams[stream_index]->r_frame_rate;// { 50, 2 };AVRational time_base_q = { 1, AV_TIME_BASE };//Duration between 2 frames (us)int64_t calc_duration = (double)(AV_TIME_BASE)*(1 / av_q2d(r_framerate1));   //内部时间戳//Parametersenc_pkt.pts = av_rescale_q(framecnt*calc_duration, time_base_q, time_base);enc_pkt.dts = enc_pkt.pts;enc_pkt.duration = av_rescale_q(calc_duration, time_base_q, time_base);/* copy packet*///转换PTS/DTS(Convert PTS/DTS)enc_pkt.pos = -1;framecnt++;ofmt_ctx->duration=enc_pkt.duration * framecnt;/* mux encoded frame */ret = av_interleaved_write_frame(ofmt_ctx, &enc_pkt);if (ret < 0)break;}return ret;
}

网上找的代码,亲测有效,服务器推荐使用Adobe Media Server 5,不会搭建服务器环境请看

Adobe Media Server 5(AMS)的安装及使用

代码工程下载:

https://download.csdn.net/download/liujiayu2/10513179

附注:

将上述代码中rtmp改写成rtsp流的时候就会出错,错误码 AVERROR_PROTOCOL_NOT_FOUND

但是使用ffmpeg命令推摄像头rtsp流的时候是没有问题的。不知道什么原因

ffmpeg推送摄像头rtmp流相关推荐

  1. FFmpeg 推送摄像头 rtsp 流

    FFmpeg 推送摄像头 rtsp 流 Windows 环境下使用 FFmpeg 推送本地 USB 摄像头为 rtsp 流,并使用 vlc 播放. 本文主要使用环境是 Windows 下的 FFmpe ...

  2. windows ffmpeg 推送摄像头数据到rtmp服务

    文本主要讲述windows系统下如何利用ffmpeg获取摄像机流并推送到rtmp服务,命令的用法前文 中有讲到过,这次是通过代码来实现.实现该项功能的基本流程如下: 图1 ffmpeg推流流程图 较前 ...

  3. linux下ffmpeg命令行推送摄像头和麦克风

    linux 下ffmpeg命令行推送摄像头和麦克风 最近学习ffmpeg,用到命令测试麦克风和摄像头,参考了很多blog,综合测试后得到如下命令. 测试系统使用的Ubuntu系统,在虚拟机中使用摄像头 ...

  4. 2023-03-05:ffmpeg推送本地视频至lal流媒体服务器(以RTMP为例),请用go语言编写。

    2023-03-05:ffmpeg推送本地视频至lal流媒体服务器(以RTMP为例),请用go语言编写. 答案2023-03-05: 使用 github.com/moonfdd/ffmpeg-go 库 ...

  5. 音视频7——安卓软编音视频数据推送到rtmp服务器

    音视频开发路线: Android 音视频开发入门指南_Jhuster的专栏的技术博客_51CTO博客_android 音视频开发入门 demo地址: videoPath/Demo8Activity.j ...

  6. FFmpeg推送命令

    ffmpeg推流命令 使用命令推送成rtp流 使用rtp发送 ffmpeg -i rtsp://admin:1qaz2wsx@192.168.10.250:554/Streaming/Channels ...

  7. 大华的支持rtmp推流吗_RTSP安防摄像机(海康大华宇视等)如何推送到RTMP流媒体服务器进行直播...

    方案介绍 目前互联网直播的CDN和标准RTMP流媒体服务器通常只能接收RTMP格式的音视频推流.目前市场上有一些自带RTMP推流的摄像机和编码器,可以直接在其rtmp推流配置里面配置推送到RTMP流媒 ...

  8. ffmpeg推rtsp、rtmp音视频流命令

    ffmpeg推rtsp.rtmp音视频流命令 rtmp流 推流 播放 rtsp流 推流 播放 原创文章禁止转载 同步发布http://www.alom.com.cn/ ffmpeg推rtsp.rtmp ...

  9. ffmpeg推送直播流的技术进展

    首先安装好NGINX并打开服务然后安装好ffmpeg然后参考:http://blog.chinaunix.net/xmlrpc.php?r=blog/article&uid=28790518& ...

最新文章

  1. 使用Lubuntu开发Android应用
  2. ECMAScript5 Object的新属性方法
  3. 同步容器和并发容器的区别
  4. 趣谈预留实例券,一文搞懂云上省钱最新玩法
  5. linux-文件路径-相对路径-绝对路径
  6. 带宽检测工具iftop
  7. .net Remoting(1)——起点,从示例做起
  8. log 日志 php tp5,TP5自定义日志记录到文件方法
  9. 《软件工程》 课后思考题
  10. 谷歌浏览器安装Octotree插件
  11. kx驱动中的DSP设置
  12. python除法取商_python 除法
  13. html5 blockquote,HTML5 Blockquote引用区块使用实例
  14. windows性能监视器API
  15. transition属性
  16. 腾讯汤道生:产业互联网时代,安全成为CEO的一把手工程
  17. colab读取Google Drive
  18. adb常用的命令【杭州多测师_王sir】【杭州多测师】
  19. D2大会资源分享(解决了GitHub下载限速)
  20. js 格式化当前时间 日期推算

热门文章

  1. 注解方式实现aop-快速入门
  2. 开始使用Spring Cloud实战微服务
  3. 如何判断对象是否存活之根搜索算法
  4. 数字证书 - Java加密与安全
  5. php arcode svg,在react中使用svg的各种方法总结(附代码)
  6. Linux Capabilities 入门教程--基础实战篇
  7. python在工厂中的应用_Python工厂方法
  8. 跨入安全的殿堂--读《Web入侵安全测试与对策》感悟
  9. 记一次重写easyui的datetimebox控件的小片段
  10. 解决 SQLSERVER 2008 无法删除作业