基于ffmpeg库实现音视频播放器代码

时间: 2024-05-25 10:05:56 浏览: 19
很抱歉,作为AI语言模型,我无法提供完整的编程实现。以下是基于ffmpeg库实现音视频播放器的一些关键步骤: 1. 引入ffmpeg库 在代码中引入ffmpeg库,包括头文件和库文件。 2. 打开输入文件 使用avformat_open_input()函数打开输入文件,获取文件的格式信息。 3. 解码音视频流 使用avcodec_find_decoder()函数查找音视频解码器,然后使用avcodec_open2()函数打开解码器。循环读取音视频帧,使用av_read_frame()函数读取帧数据,使用avcodec_send_packet()函数发送数据包,使用avcodec_receive_frame()函数接收解码后的帧数据。 4. 播放音视频帧 使用SDL库创建音频和视频播放器,使用SDL_CreateThread()函数创建线程,循环读取音视频帧数据,使用SDL_QueueAudio()函数将音频数据添加到音频缓冲中,使用SDL_RenderCopy()函数将视频数据渲染到窗口上。 5. 关闭解码器和输入文件 在播放完毕后,使用avcodec_close()函数关闭解码器,使用avformat_close_input()函数关闭输入文件。 以上是基于ffmpeg库实现音视频播放器的一些关键步骤,具体实现需要根据具体需求进行调整。
相关问题

基于ffmpeg的简单音视频播放器的demo

以下是基于ffmpeg的简单音视频播放器的demo的代码,使用C++语言编写: ```c++ #include <iostream> #include <string> #include <thread> #include <chrono> extern "C" { #include <libavformat/avformat.h> #include <libavcodec/avcodec.h> #include <libswscale/swscale.h> #include <libavutil/imgutils.h> } using namespace std; int main(int argc, char* argv[]) { if (argc != 2) { cout << "Usage: " << argv[0] << " filename" << endl; return 1; } // Initialize FFmpeg av_register_all(); avcodec_register_all(); // Open video file AVFormatContext* format_ctx = nullptr; if (avformat_open_input(&format_ctx, argv[1], nullptr, nullptr) != 0) { cerr << "Error: Failed to open file " << argv[1] << endl; return 1; } // Retrieve stream information if (avformat_find_stream_info(format_ctx, nullptr) < 0) { cerr << "Error: Failed to retrieve stream information" << endl; return 1; } // Find the first video stream int video_stream_index = -1; AVCodecParameters* codec_params = nullptr; AVCodec* codec = nullptr; AVCodecContext* codec_ctx = nullptr; for (int i = 0; i < format_ctx->nb_streams; i++) { codec_params = format_ctx->streams[i]->codecpar; if (codec_params->codec_type == AVMEDIA_TYPE_VIDEO) { video_stream_index = i; codec = avcodec_find_decoder(codec_params->codec_id); if (codec == nullptr) { cerr << "Error: Unsupported codec" << endl; return 1; } codec_ctx = avcodec_alloc_context3(codec); if (codec_ctx == nullptr) { cerr << "Error: Failed to allocate codec context" << endl; return 1; } if (avcodec_parameters_to_context(codec_ctx, codec_params) < 0) { cerr << "Error: Failed to copy codec parameters to codec context" << endl; return 1; } if (avcodec_open2(codec_ctx, codec, nullptr) < 0) { cerr << "Error: Failed to open codec" << endl; return 1; } break; } } if (video_stream_index == -1) { cerr << "Error: Failed to find video stream" << endl; return 1; } // Allocate video frame and buffer AVFrame* frame = av_frame_alloc(); if (frame == nullptr) { cerr << "Error: Failed to allocate video frame" << endl; return 1; } AVFrame* rgb_frame = av_frame_alloc(); if (rgb_frame == nullptr) { cerr << "Error: Failed to allocate RGB video frame" << endl; return 1; } uint8_t* buffer = nullptr; int num_bytes = av_image_get_buffer_size(AV_PIX_FMT_RGB24, codec_ctx->width, codec_ctx->height, 1); buffer = (uint8_t*)av_malloc(num_bytes * sizeof(uint8_t)); if (buffer == nullptr) { cerr << "Error: Failed to allocate buffer" << endl; return 1; } av_image_fill_arrays(rgb_frame->data, rgb_frame->linesize, buffer, AV_PIX_FMT_RGB24, codec_ctx->width, codec_ctx->height, 1); // Allocate SwsContext SwsContext* sws_ctx = sws_getContext(codec_ctx->width, codec_ctx->height, codec_ctx->pix_fmt, codec_ctx->width, codec_ctx->height, AV_PIX_FMT_RGB24, SWS_BILINEAR, nullptr, nullptr, nullptr); if (sws_ctx == nullptr) { cerr << "Error: Failed to allocate SwsContext" << endl; return 1; } // Initialize window and renderer SDL_Window* window = nullptr; SDL_Renderer* renderer = nullptr; if (SDL_Init(SDL_INIT_VIDEO) < 0) { cerr << "Error: Failed to initialize SDL" << endl; return 1; } window = SDL_CreateWindow("Video Player", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, codec_ctx->width, codec_ctx->height, SDL_WINDOW_SHOWN); if (window == nullptr) { cerr << "Error: Failed to create window" << endl; return 1; } renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED); if (renderer == nullptr) { cerr << "Error: Failed to create renderer" << endl; return 1; } // Read packets from stream and decode AVPacket packet; while (av_read_frame(format_ctx, &packet) >= 0) { if (packet.stream_index == video_stream_index) { avcodec_send_packet(codec_ctx, &packet); while (avcodec_receive_frame(codec_ctx, frame) == 0) { sws_scale(sws_ctx, frame->data, frame->linesize, 0, frame->height, rgb_frame->data, rgb_frame->linesize); SDL_UpdateTexture(SDL_CreateTextureFromSurface(renderer, av_frame_get_surface(rgb_frame)), nullptr, nullptr, 0); SDL_RenderClear(renderer); SDL_RenderCopy(renderer, SDL_CreateTextureFromSurface(renderer, av_frame_get_surface(rgb_frame)), nullptr, nullptr); SDL_RenderPresent(renderer); this_thread::sleep_for(chrono::milliseconds(10)); } } av_packet_unref(&packet); } // Clean up av_frame_free(&frame); av_frame_free(&rgb_frame); av_free(buffer); avcodec_free_context(&codec_ctx); avformat_close_input(&format_ctx); SDL_DestroyRenderer(renderer); SDL_DestroyWindow(window); SDL_Quit(); return 0; } ``` 这个demo使用SDL库来显示视频,使用FFmpeg库来解码视频。在运行时需要提供一个视频文件的路径作为参数。可以根据需要进行修改和扩展。

基于ffmpeg的简单音视频播放器的demoC语言

以下是一个基于FFmpeg的简单音视频播放器的demo代码,使用C语言编写: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <pthread.h> #include <SDL2/SDL.h> #include <libavformat/avformat.h> #include <libswscale/swscale.h> #define SDL_AUDIO_BUFFER_SIZE 1024 #define MAX_AUDIO_FRAME_SIZE 192000 typedef struct PacketQueue { AVPacketList *first_pkt, *last_pkt; int nb_packets; int size; pthread_mutex_t mutex; pthread_cond_t cond; } PacketQueue; PacketQueue audioq; int quit = 0; void packet_queue_init(PacketQueue *q) { memset(q, 0, sizeof(PacketQueue)); pthread_mutex_init(&q->mutex, NULL); pthread_cond_init(&q->cond, NULL); } int packet_queue_put(PacketQueue *q, AVPacket *pkt) { AVPacketList *pkt1; if (av_packet_ref(pkt, pkt) < 0) { return -1; } pkt1 = (AVPacketList*) av_malloc(sizeof(AVPacketList)); if (!pkt1) { return -1; } pkt1->pkt = *pkt; pkt1->next = NULL; pthread_mutex_lock(&q->mutex); if (!q->last_pkt) { q->first_pkt = pkt1; } else { q->last_pkt->next = pkt1; } q->last_pkt = pkt1; q->nb_packets++; q->size += pkt1->pkt.size; pthread_cond_signal(&q->cond); pthread_mutex_unlock(&q->mutex); return 0; } int packet_queue_get(PacketQueue *q, AVPacket *pkt, int block) { AVPacketList *pkt1; int ret; pthread_mutex_lock(&q->mutex); for (;;) { if (quit) { ret = -1; break; } pkt1 = q->first_pkt; if (pkt1) { q->first_pkt = pkt1->next; if (!q->first_pkt) { q->last_pkt = NULL; } q->nb_packets--; q->size -= pkt1->pkt.size; *pkt = pkt1->pkt; av_free(pkt1); ret = 1; break; } else if (!block) { ret = 0; break; } else { pthread_cond_wait(&q->cond, &q->mutex); } } pthread_mutex_unlock(&q->mutex); return ret; } int audio_decode_frame(AVCodecContext *aCodecCtx, uint8_t *audio_buf, int buf_size) { static AVPacket pkt; static uint8_t *audio_pkt_data = NULL; static int audio_pkt_size = 0; int len1, data_size = 0; for (;;) { while (audio_pkt_size > 0) { int got_frame = 0; len1 = avcodec_decode_audio4(aCodecCtx, &aFrame, &got_frame, &pkt); if (len1 < 0) { audio_pkt_size = 0; break; } audio_pkt_data += len1; audio_pkt_size -= len1; if (got_frame) { data_size = av_samples_get_buffer_size(NULL, aCodecCtx->channels, aFrame.nb_samples, aCodecCtx->sample_fmt, 1); memcpy(audio_buf, aFrame.data[0], data_size); } if (data_size <= 0) { continue; } return data_size; } if (pkt.data) { av_packet_unref(&pkt); } if (quit) { return -1; } if (packet_queue_get(&audioq, &pkt, 1) < 0) { return -1; } audio_pkt_data = pkt.data; audio_pkt_size = pkt.size; } } void audio_callback(void *userdata, Uint8 *stream, int len) { AVCodecContext *aCodecCtx = (AVCodecContext*) userdata; int len1, audio_size; while (len > 0) { if (audio_buf_index >= audio_buf_size) { audio_size = audio_decode_frame(aCodecCtx, audio_buf, sizeof(audio_buf)); if (audio_size < 0) { silence_buf(stream, len); return; } audio_buf_size = audio_size; audio_buf_index = 0; } len1 = audio_buf_size - audio_buf_index; if (len1 > len) { len1 = len; } memcpy(stream, (uint8_t*)audio_buf + audio_buf_index, len1); len -= len1; stream += len1; audio_buf_index += len1; } } void silence_buf(Uint8 *stream, int len) { int i; for (i = 0; i < len; i++) { stream[i] = 0; } } void audio_thread(void *arg) { AVCodecContext *aCodecCtx = (AVCodecContext*) arg; SDL_AudioSpec wanted_spec, spec; int ret; wanted_spec.freq = aCodecCtx->sample_rate; wanted_spec.format = AUDIO_S16SYS; wanted_spec.channels = aCodecCtx->channels; wanted_spec.silence = 0; wanted_spec.samples = SDL_AUDIO_BUFFER_SIZE; wanted_spec.callback = audio_callback; wanted_spec.userdata = aCodecCtx; if (SDL_OpenAudio(&wanted_spec, &spec) < 0) { fprintf(stderr, "SDL_OpenAudio: %s\n", SDL_GetError()); return; } if (spec.format != AUDIO_S16SYS) { fprintf(stderr, "SDL advised audio format %d is not supported!\n", spec.format); return; } while (1) { if (quit) { break; } SDL_Delay(100); } SDL_CloseAudio(); } int main(int argc, char *argv[]) { AVFormatContext *pFormatCtx = NULL; AVCodecContext *aCodecCtxOrig = NULL, *aCodecCtx = NULL; AVCodec *aCodec = NULL; pthread_t audio_tid; AVPacket pkt; int audioStream = -1, i; av_register_all(); if (SDL_Init(SDL_INIT_AUDIO) < 0) { fprintf(stderr, "SDL_Init: %s\n", SDL_GetError()); return -1; } if (avformat_open_input(&pFormatCtx, argv[1], NULL, NULL) != 0) { return -1; } if (avformat_find_stream_info(pFormatCtx, NULL) < 0) { return -1; } av_dump_format(pFormatCtx, 0, argv[1], 0); for (i = 0; i < pFormatCtx->nb_streams; i++) { if (pFormatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO && audioStream < 0) { audioStream = i; } } if (audioStream == -1) { return -1; } aCodecCtxOrig = pFormatCtx->streams[audioStream]->codec; aCodec = avcodec_find_decoder(aCodecCtxOrig->codec_id); if (!aCodec) { return -1; } aCodecCtx = avcodec_alloc_context3(aCodec); if (avcodec_parameters_to_context(aCodecCtx, pFormatCtx->streams[audioStream]->codecpar) < 0) { return -1; } if (avcodec_open2(aCodecCtx, aCodec, NULL) < 0) { return -1; } packet_queue_init(&audioq); av_init_packet(&pkt); pthread_create(&audio_tid, NULL, audio_thread, aCodecCtx); while (av_read_frame(pFormatCtx, &pkt) >= 0) { if (pkt.stream_index == audioStream) { packet_queue_put(&audioq, &pkt); } else { av_packet_unref(&pkt); } } while (!quit) { SDL_Delay(100); } quit = 1; pthread_join(audio_tid, NULL); avcodec_free_context(&aCodecCtx); avformat_close_input(&pFormatCtx); return 0; } ``` 这段代码中使用了FFmpeg库来解码音频数据,SDL库来播放音频数据。其中,PacketQueue结构体用于存储AVPacket数据,audio_decode_frame函数用于解码音频数据,audio_callback函数用于播放音频数据,audio_thread函数用于启动SDL音频线程。在主函数中,首先使用avformat_open_input函数打开音视频文件,然后遍历文件中所有的流,找到音频流并记录其索引,接着使用avcodec_find_decoder函数查找合适的解码器,使用avcodec_alloc_context3函数分配解码器上下文,使用avcodec_parameters_to_context函数将AVCodecParameters转换为AVCodecContext,使用avcodec_open2函数打开解码器,然后启动音频线程,读取音频数据并存入PacketQueue结构体中,最后等待音频线程结束并释放资源。

相关推荐

最新推荐

recommend-type

python 实现多线程下载m3u8格式视频并使用fmmpeg合并

`ffmpeg`是一个强大的音视频处理工具,它可以处理各种格式的音视频文件,包括m3u8和TS。在这个例子中,我们使用`-f concat`选项告诉ffmpeg我们将使用一个包含所有TS文件名的列表(即前面创建的concatfile)来合并...
recommend-type

FFMpeg框架代码阅读

理解 FFmpeg 的代码框架和组件间的交互对于开发自定义的音视频处理程序或者进行二次开发是非常重要的。这包括了解如何编写新的编码器、解码器、复用器或解复用器,以及如何将它们集成到 FFmpeg 的生态系统中。同时,...
recommend-type

毕业设计论文-基于RTSP的视频监控系统.doc

FFmpeg是一个开源的多媒体处理工具集,包含了编解码器、音视频转换、流处理等功能。x264是H.264/AVC编码器的开源实现,H.264是目前广泛使用的视频编码标准,能提供高画质的同时,压缩效率也相对较高。在视频监控系统...
recommend-type

GO婚礼设计创业计划:技术驱动的婚庆服务

"婚礼GO网站创业计划书" 在创建婚礼GO网站的创业计划书中,创业者首先阐述了企业的核心业务——GO婚礼设计,专注于提供计算机软件销售和技术开发、技术服务,以及与婚礼相关的各种服务,如APP制作、网页设计、弱电工程安装等。企业类型被定义为服务类,涵盖了一系列与信息技术和婚礼策划相关的业务。 创业者的个人经历显示了他对行业的理解和投入。他曾在北京某科技公司工作,积累了吃苦耐劳的精神和实践经验。此外,他在大学期间担任班长,锻炼了团队管理和领导能力。他还参加了SYB创业培训班,系统地学习了创业意识、计划制定等关键技能。 市场评估部分,目标顾客定位为本地的结婚人群,特别是中等和中上收入者。根据数据显示,广州市内有14家婚庆公司,该企业预计能占据7%的市场份额。广州每年约有1万对新人结婚,公司目标接待200对新人,显示出明确的市场切入点和增长潜力。 市场营销计划是创业成功的关键。尽管文档中没有详细列出具体的营销策略,但可以推断,企业可能通过线上线下结合的方式,利用社交媒体、网络广告和本地推广活动来吸引目标客户。此外,提供高质量的技术解决方案和服务,以区别于竞争对手,可能是其市场差异化策略的一部分。 在组织结构方面,未详细说明,但可以预期包括了技术开发团队、销售与市场部门、客户服务和支持团队,以及可能的行政和财务部门。 在财务规划上,文档提到了固定资产和折旧、流动资金需求、销售收入预测、销售和成本计划以及现金流量计划。这表明创业者已经考虑了启动和运营的初期成本,以及未来12个月的收入预测,旨在确保企业的现金流稳定,并有可能享受政府对大学生初创企业的税收优惠政策。 总结来说,婚礼GO网站的创业计划书详尽地涵盖了企业概述、创业者背景、市场分析、营销策略、组织结构和财务规划等方面,为初创企业的成功奠定了坚实的基础。这份计划书显示了创业者对市场的深刻理解,以及对技术和婚礼行业的专业认识,有望在竞争激烈的婚庆市场中找到一席之地。
recommend-type

管理建模和仿真的文件

管理Boualem Benatallah引用此版本:布阿利姆·贝纳塔拉。管理建模和仿真。约瑟夫-傅立叶大学-格勒诺布尔第一大学,1996年。法语。NNT:电话:00345357HAL ID:电话:00345357https://theses.hal.science/tel-003453572008年12月9日提交HAL是一个多学科的开放存取档案馆,用于存放和传播科学研究论文,无论它们是否被公开。论文可以来自法国或国外的教学和研究机构,也可以来自公共或私人研究中心。L’archive ouverte pluridisciplinaire
recommend-type

【基础】PostgreSQL的安装和配置步骤

![【基础】PostgreSQL的安装和配置步骤](https://img-blog.csdnimg.cn/direct/8e80154f78dd45e4b061508286f9d090.png) # 2.1 安装前的准备工作 ### 2.1.1 系统要求 PostgreSQL 对系统硬件和软件环境有一定要求,具体如下: - 操作系统:支持 Linux、Windows、macOS 等主流操作系统。 - CPU:推荐使用多核 CPU,以提高数据库处理性能。 - 内存:根据数据库规模和并发量确定,一般建议 8GB 以上。 - 硬盘:数据库文件和临时文件需要占用一定空间,建议预留足够的空间。
recommend-type

字节跳动面试题java

字节跳动作为一家知名的互联网公司,在面试Java开发者时可能会关注以下几个方面的问题: 1. **基础技能**:Java语言的核心语法、异常处理、内存管理、集合框架、IO操作等是否熟练掌握。 2. **面向对象编程**:多态、封装、继承的理解和应用,可能会涉及设计模式的提问。 3. **并发编程**:Java并发API(synchronized、volatile、Future、ExecutorService等)的使用,以及对并发模型(线程池、并发容器等)的理解。 4. **框架知识**:Spring Boot、MyBatis、Redis等常用框架的原理和使用经验。 5. **数据库相
recommend-type

微信行业发展现状及未来发展趋势分析

微信行业发展现状及未来行业发展趋势分析 微信作为移动互联网的基础设施,已经成为流量枢纽,月活跃账户达到10.4亿,同增10.9%,是全国用户量最多的手机App。微信的活跃账户从2012年起步月活用户仅为5900万人左右,伴随中国移动互联网进程的不断推进,微信的活跃账户一直维持稳步增长,在2014-2017年年末分别达到5亿月活、6.97亿月活、8.89亿月活和9.89亿月活。 微信月活发展历程显示,微信的用户数量增长已经开始呈现乏力趋势。微信在2018年3月日活达到6.89亿人,同比增长5.5%,环比上个月增长1.7%。微信的日活同比增速下滑至20%以下,并在2017年年底下滑至7.7%左右。微信DAU/MAU的比例也一直较为稳定,从2016年以来一直维持75%-80%左右的比例,用户的粘性极强,继续提升的空间并不大。 微信作为流量枢纽,已经成为移动互联网的基础设施,月活跃账户达到10.4亿,同增10.9%,是全国用户量最多的手机App。微信的活跃账户从2012年起步月活用户仅为5900万人左右,伴随中国移动互联网进程的不断推进,微信的活跃账户一直维持稳步增长,在2014-2017年年末分别达到5亿月活、6.97亿月活、8.89亿月活和9.89亿月活。 微信的用户数量增长已经开始呈现乏力趋势,这是因为微信自身也在重新寻求新的增长点。微信日活发展历程显示,微信的用户数量增长已经开始呈现乏力趋势。微信在2018年3月日活达到6.89亿人,同比增长5.5%,环比上个月增长1.7%。微信的日活同比增速下滑至20%以下,并在2017年年底下滑至7.7%左右。 微信DAU/MAU的比例也一直较为稳定,从2016年以来一直维持75%-80%左右的比例,用户的粘性极强,继续提升的空间并不大。因此,在整体用户数量开始触达天花板的时候,微信自身也在重新寻求新的增长点。 中国的整体移动互联网人均单日使用时长已经较高水平。18Q1中国移动互联网的月度总时长达到了77千亿分钟,环比17Q4增长了14%,单人日均使用时长达到了273分钟,环比17Q4增长了15%。而根据抽样统计,社交始终占据用户时长的最大一部分。2018年3月份,社交软件占据移动互联网35%左右的时长,相比2015年减少了约10pct,但仍然是移动互联网当中最大的时长占据者。 争夺社交软件份额的主要系娱乐类App,目前占比达到约32%左右。移动端的流量时长分布远比PC端更加集中,通常认为“搜索下載”和“网站导航”为PC时代的流量枢纽,但根据统计,搜索的用户量约为4.5亿,为各类应用最高,但其时长占比约为5%左右,落后于网络视频的13%左右位于第二名。PC时代的网络社交时长占比约为4%-5%,基本与搜索相当,但其流量分发能力远弱于搜索。 微信作为移动互联网的基础设施,已经成为流量枢纽,月活跃账户达到10.4亿,同增10.9%,是全国用户量最多的手机App。微信的活跃账户从2012年起步月活用户仅为5900万人左右,伴随中国移动互联网进程的不断推进,微信的活跃账户一直维持稳步增长,在2014-2017年年末分别达到5亿月活、6.97亿月活、8.89亿月活和9.89亿月活。 微信的用户数量增长已经开始呈现乏力趋势,这是因为微信自身也在重新寻求新的增长点。微信日活发展历程显示,微信的用户数量增长已经开始呈现乏力趋势。微信在2018年3月日活达到6.89亿人,同比增长5.5%,环比上个月增长1.7%。微信的日活同比增速下滑至20%以下,并在2017年年底下滑至7.7%左右。 微信DAU/MAU的比例也一直较为稳定,从2016年以来一直维持75%-80%左右的比例,用户的粘性极强,继续提升的空间并不大。因此,在整体用户数量开始触达天花板的时候,微信自身也在重新寻求新的增长点。 微信作为移动互联网的基础设施,已经成为流量枢纽,月活跃账户达到10.4亿,同增10.9%,是全国用户量最多的手机App。微信的活跃账户从2012年起步月活用户仅为5900万人左右,伴随中国移动互联网进程的不断推进,微信的活跃账户一直维持稳步增长,在2014-2017年年末分别达到5亿月活、6.97亿月活、8.89亿月活和9.89亿月活。 微信的用户数量增长已经开始呈现乏力趋势,这是因为微信自身也在重新寻求新的增长点。微信日活发展历程显示,微信的用户数量增长已经开始呈现乏力趋势。微信在2018年3月日活达到6.89亿人,同比增长5.5%,环比上个月增长1.7%。微信的日活同比增速下滑至20%以下,并在2017年年底下滑至7.7%左右。 微信DAU/MAU的比例也一直较为稳定,从2016年以来一直维持75%-80%左右的比例,用户的粘性极强,继续提升的空间并不大。因此,在整体用户数量开始触达天花板的时候,微信自身也在重新寻求新的增长点。 微信作为移动互联网的基础设施,已经成为流量枢纽,月活跃账户达到10.4亿,同增10.9%,是全国用户量最多的手机App。微信的活跃账户从2012年起步月活用户仅为5900万人左右,伴随中国移动互联网进程的不断推进,微信的活跃账户一直维持稳步增长,在2014-2017年年末分别达到5亿月活、6.97亿月活、8.89亿月活和9.89亿月活。 微信的用户数量增长已经开始呈现乏力趋势,这是因为微信自身也在重新寻求新的增长点。微信日活发展历程显示,微信的用户数量增长已经开始呈现乏力趋势。微信在2018年3月日活达到6.89亿人,同比增长5.5%,环比上个月增长1.7%。微信的日活同比增速下滑至20%以下,并在2017年年底下滑至7.7%左右。 微信DAU/MAU的比例也一直较为稳定,从2016年以来一直维持75%-80%左右的比例,用户的粘性极强,继续提升的空间并不大。因此,在整体用户数量开始触达天花板的时候,微信自身也在重新寻求新的增长点。
recommend-type

"互动学习:行动中的多样性与论文攻读经历"

多样性她- 事实上SCI NCES你的时间表ECOLEDO C Tora SC和NCESPOUR l’Ingén学习互动,互动学习以行动为中心的强化学习学会互动,互动学习,以行动为中心的强化学习计算机科学博士论文于2021年9月28日在Villeneuve d'Asq公开支持马修·瑟林评审团主席法布里斯·勒菲弗尔阿维尼翁大学教授论文指导奥利维尔·皮耶昆谷歌研究教授:智囊团论文联合主任菲利普·普雷教授,大学。里尔/CRISTAL/因里亚报告员奥利维耶·西格德索邦大学报告员卢多维奇·德诺耶教授,Facebook /索邦大学审查员越南圣迈IMT Atlantic高级讲师邀请弗洛里安·斯特鲁布博士,Deepmind对于那些及时看到自己错误的人...3谢谢你首先,我要感谢我的两位博士生导师Olivier和Philippe。奥利维尔,"站在巨人的肩膀上"这句话对你来说完全有意义了。从科学上讲,你知道在这篇论文的(许多)错误中,你是我可以依
recommend-type

【基础】安装MySQL:从下载到配置的完整指南

![python数据库编程合集](https://opengraph.githubassets.com/f5c38590c64cc0ea56ef235eff4fb5d5675e3c699a36ce388d1ffc280bd77681/mongodb/mongo-python-driver) # 1. MySQL数据库简介 MySQL是一种开源的关系型数据库管理系统(RDBMS),因其高性能、可扩展性和易用性而闻名。它广泛应用于各种规模的应用程序,从小型网站到大型企业系统。 MySQL使用结构化查询语言(SQL)来管理数据。SQL是一种标准化语言,允许用户通过简单的命令创建、读取、更新和删除