本期内容主要包括
- 摄像机坐标系求解(郑雨薇)
- 弗洛伊德算法简介(许云华)
- 线程状态图(线程生命周期)(张艳强)
- gl中的纹理映射(冯树勋)
- 纹理贴图学习(陈伟)
- 服务器负载均衡(张辰)
- 双线性差值(许佳佳)
- HashMap简介(江丁魁)
- 总结本期知识点
要定义一个摄像机,需要摄像机在世界坐标的位置,它观察的方向(z轴反方向),指向右侧的向量(x)轴,以及上轴(y轴) 。
摄像机位置
使用一个三维向量来表示位置的坐标,glm::vec3 cameraPos = glm::vec3(0.0f, 0.0f, 3.0f);
z轴方向
摄像机观察的反方向,即用观察目标指向摄像机位置即可。
glm::vec3 cameraTarget = glm::vec3(0.0f, 0.0f, 0.0f); glm::vec3 cameraDirection = glm::normalize(cameraPos - cameraTarget);
待续(未收到内容)
-
进程(process),指的是一个正在运行中的可执行文件。每一个进程都拥有独立的虚拟内存空间和系统资源,包括端口权限等,且至少包含一个主线程和任意数量的辅助线程。另外,当一个进程的主线程退出时,这个进程就结束了;
-
线程(thread),指的是一个独立的代码执行路径,也就是说线程是代码执行路径的最小分支(CPU调度的最小单位,不具有独立内存,多个线程共享进程的资源)。在 iOS 中,线程的底层实现是基于 POSIX threads API 的,也就是我们常说的 pthreads ;
-
总结:进程是资源分配的基本单位,线程是调度的基本单位。进程包含线程,线程共用进程的资源
更多信息请移步至我的博客,关于进程和线程的详细解释跳转
gl中的纹理映射
glGenTextures
纹理生成
glBindTexture
纹理绑定
GL_TEXTURE_2D 首次绑定后纹理成为2d纹理
GL_TEXTURE_CUBE_MAP 首次绑定后纹理成为3d纹理
glActiveTexture
纹理激活
至少有8个,查询GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS获取;从0开始
glGenerateMipmap
为当前激活纹理生成mip纹理
target 当前激活纹理的绑定类型,必须为GL_TEXTURE_2D或 GL_TEXTURE_CUBE_MAP
glTexParameter
参数类型:
GL_TEXTURE_MIN_FILTER 缩小情况的映射,可以指定mipmap,分为nearest和linear方式,一个是最近点,一个取临近四个点的线性插值
GL_TEXTURE_MAG_FILTER 放大情况的映射,分为nearest和linear方式
GL_TEXTURE_WRAP_S 纹理坐标映射模式,GL_CLAMP_TO_EDGE,GL_MIRRORED_REPEAT,GL_REPEAT,分别为边界裁剪,镜像重复和重复
GL_TEXTURE_WRAP_T 同GL_TEXTURE_WRAP_S
glTexImage2D
Level 指定mipmap级别
internalformat gpu中texture像素格式,GL_ALPHA, GL_LUMINANCE, GL_LUMINANCE_ALPHA, GL_RGB, GL_RGBA
format cpu中像素格式,必须和internalformat一致
type cpu中像素类型,GL_UNSIGNED_BYTE, GL_UNSIGNED_SHORT_5_6_5, GL_UNSIGNED_SHORT_4_4_4_4, and GL_UNSIGNED_SHORT_5_5_5_1
Data cpu中像素指针; 如果为空,gpu中会分配width x height的存储,但是处于未定义状态不可使用,通过glTexSubImage2D来初始化
glTexSubImage2D
xoffset, yoffset, width, height界定了更新的区域,但是不能超过gpu中纹理区域
format cpu中像素格式,必须和internalformat一致
type cpu中像素类型,GL_UNSIGNED_BYTE, GL_UNSIGNED_SHORT_5_6_5, GL_UNSIGNED_SHORT_4_4_4_4, and GL_UNSIGNED_SHORT_5_5_5_1
data 替代像素
glPixelStorei
影响像素对齐
GL_PACK_ALIGNMENT 影响gpu到cpu的像素传输,可选1,2,4,8
GL_UNPACK_ALIGNMENT 影响cpu到gpu的像素传输,可选1,2,4,8;上述glTexImage2D,glTexSubImage2D需要谨慎设置该参数
glCopyTexImage2D
同glTexImage2D,但是像素数据部分指向当前的framebuffer。
width 2d纹理至少64像素,3d纹理至少16像素
Height 2d纹理至少64像素,3d纹理至少16像素
glCopyTexSubImage2D
同glTexSubImage2D,但是像素数据部分指向当前的framebuffer。
glCompressedTexImage2D
扩展接口,压缩纹理格式需要查询GL_NUM_COMPRESSED_TEXTURE_FORMATS, GL_COMPRESSED_TEXTURE_FORMATS
width 2d纹理至少64像素,3d纹理至少16像素
height 2d纹理至少64像素,3d纹理至少16像素
internalformat 指定压缩数据的格式
imageSize 指定压缩数据的大小
data 压缩数据的指针
glCompressedTexSubImage2D
参数解释同glCompressedTexImage2D
其中xoffset, yoffset, width, height界定了更新的区域, 但是不能超过gpu中纹理区域; width, height没有最小限制
SDL(Simple DirectMedia Layer)是一套跨平台多媒体开发库,由C语言写成。SDL提供了数种控制声音、图像、输出入的函数,让开发者使用同一套代码就可以开发出跨平台的应用。例如图像是封装的OpenGL或者Direct3D,音频也是封装了各个平台的底层音频接口如OpenSL。直接移植SDL到各个平台上,可以很便利地开发出播放器,但灵活性不够,可以参考,自行实现视频、音频播放以及音视频同步。
// SDL_ffmpeg_demo
//
// Created by cw on 2018/9/3.
// Copyright © 2018年 cw. All rights reserved.
//
#include <stdio.h>
extern "C"{
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
#include <libavutil/avutil.h>
#include <libavutil/imgutils.h>
#include <libavresample/avresample.h>
#include <libswscale/swscale.h>
#include <SDL2/SDL.h>
}
int main(int argc, char* argv[])
{
AVFormatContext *pFormatContext;
AVCodec *pCodec;
AVCodecContext *pCodecContext;
AVCodecParameters *pCodecParams;
AVFrame *pFrame, *pFrameYUV;
AVPacket *packet;
struct SwsContext *img_convert_ctx;
SDL_Window *screen;
SDL_Renderer *sdlRenderer;
SDL_Texture *sdlTexture;
SDL_Rect sdlRect;
unsigned char *out_buffer;
int videoIndex = -1;
int screen_w, screen_h;
char filepath[]="/Users/cw/Desktop/ios/SDL_ffmpeg_demo/SDL_ffmpeg_demo/bigbuckbunny_480x272.h264";
pFormatContext = avformat_alloc_context();
if (avformat_open_input(&pFormatContext, filepath, nullptr, nullptr)!=0) {
printf("could not open input stream. \n");
return -1;
}
if (avformat_find_stream_info(pFormatContext, nullptr)<0) {
printf("could not find stream information. \n");
return -1;
}
for (int i=0; i<pFormatContext->nb_streams; ++i) {
if (pFormatContext->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
videoIndex = i;
break;
}
}
if (videoIndex == -1) {
printf("could not find video stream. \n");
return -1;
}
pCodecParams = pFormatContext->streams[videoIndex]->codecpar;
pCodec = avcodec_find_decoder(pCodecParams->codec_id);
if (pCodec == nullptr) {
printf("could not find video codec. \n");
return -1;
}
pCodecContext = avcodec_alloc_context3(pCodec);
avcodec_parameters_to_context(pCodecContext, pCodecParams);
if (avcodec_open2(pCodecContext, pCodec, nullptr)<0) {
printf("could not open video codec");
return -1;
}
pFrame = av_frame_alloc();
pFrameYUV = av_frame_alloc();
out_buffer = (unsigned char *)av_malloc(av_image_get_buffer_size(AV_PIX_FMT_YUV420P, pCodecParams->width, pCodecParams->height, 1));
av_image_fill_arrays(pFrameYUV->data, pFrameYUV->linesize, out_buffer, AV_PIX_FMT_YUV420P, pCodecParams->width, pCodecParams->height, 1);
packet = (AVPacket *)av_malloc(sizeof(AVPacket));
printf("--------------File Info begin ------------\n");
av_dump_format(pFormatContext, videoIndex, filepath, 0);
printf("--------------File Info end---------------\n");
img_convert_ctx = sws_getContext(pCodecParams->width, pCodecParams->height, pCodecContext->pix_fmt, pCodecParams->width, pCodecParams->height, AV_PIX_FMT_YUV420P, SWS_BICUBIC, nullptr, nullptr, nullptr);
//SDL init begin
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER)) {
printf("could not init sdl, %s ", SDL_GetError());
return -1;
}
screen_w = pCodecParams->width;
screen_h = pCodecParams->height;
screen = SDL_CreateWindow("My First SDL2 demo", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, screen_w, screen_h, SDL_WINDOW_OPENGL);
if (!screen) {
printf("could not create sdl window %s.\n", SDL_GetError());
return -1;
}
sdlRenderer = SDL_CreateRenderer(screen, -1, 0);
sdlTexture = SDL_CreateTexture(sdlRenderer, SDL_PIXELFORMAT_IYUV, SDL_TEXTUREACCESS_STREAMING, screen_w, screen_h);
sdlRect.x = 0;
sdlRect.y = 0;
sdlRect.w = screen_w;
sdlRect.h = screen_h;
//SDL init end
while (av_read_frame(pFormatContext, packet)==0) {
//video
if (packet->stream_index == videoIndex) {
int ret = avcodec_send_packet(pCodecContext, packet);
if (ret !=0) {
printf("avcodec_send_packet error. \n");
return -1;
}
int got_picture = avcodec_receive_frame(pCodecContext, pFrame);
if (got_picture == 0) {
sws_scale(img_convert_ctx, pFrame->data, pFrame->linesize, 0, pCodecParams->height, pFrameYUV->data, pFrameYUV->linesize);
//SDL
SDL_UpdateYUVTexture(sdlTexture, &sdlRect, pFrameYUV->data[0], pFrameYUV->linesize[0], pFrameYUV->data[1], pFrameYUV->linesize[1], pFrameYUV->data[2], pFrameYUV->linesize[2]);
SDL_RenderClear(sdlRenderer);
SDL_RenderCopy(sdlRenderer, sdlTexture, nullptr, &sdlRect);
SDL_RenderPresent(sdlRenderer);
SDL_Delay(40);
}
}
av_packet_unref(packet);
}
sws_freeContext(img_convert_ctx);
SDL_Quit();
av_frame_free(&pFrameYUV);
av_frame_free(&pFrame);
avcodec_close(pCodecContext);
avformat_close_input(&pFormatContext);
// avcodec_parameters_free(&pCodecParams);
return 0;
}
待补(未收到内容)
假设我们已知坐标 (x0, y0) 与 (x1, y1),要得到 [x0, x1] 区间内某一位置 x 在直线上的值。根据图中所示,我们得到
由于 x 值已知,所以可以从公式得到 y 的值
假如我们想得到未知函数 f 在点 P = (x, y) 的值,假设我们已知函数 f 在 Q11 = (x1, y1)、Q12 = (x1, y2), Q21 = (x2, y1) 以及 Q22 = (x2, y2) 四个点的值。首先在 x 方向进行线性插值,得到:
待补(未收到内容)
待补()