读取jpg文件到HBITMAP

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
HBITMAP loadPictureFromFile(LPCTSTR szFile)
{
	HANDLE hFile = CreateFile(szFile, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
	if (INVALID_HANDLE_VALUE == hFile)
		return NULL;
 
	DWORD dwFileSize = GetFileSize(hFile, NULL);
 
	LPVOID pvData = NULL;
	HGLOBAL hGlobal = GlobalAlloc(GMEM_MOVEABLE, dwFileSize);
 
	pvData = GlobalLock(hGlobal);
 
	DWORD dwBytesRead = 0;
	BOOL bRead = ReadFile(hFile, pvData, dwFileSize, &dwBytesRead, NULL);
	GlobalUnlock(hGlobal);
	CloseHandle(hFile);
 
	LPSTREAM pStm = NULL;
	HRESULT hr = CreateStreamOnHGlobal(hGlobal, TRUE, &pStm);
 
	LPPICTURE gpPicture;
 
	hr = ::OleLoadPicture(pStm, dwFileSize, FALSE, IID_IPicture, (LPVOID *)&gpPicture);
 
	pStm->Release();
 
	OLE_HANDLE picHandle;
	gpPicture->get_Handle(&picHandle);
	HDC hdc = ::CreateCompatibleDC(NULL);
	::SelectObject(hdc, (HGDIOBJ)picHandle);
 
	HBITMAP hRet = (HBITMAP)::GetCurrentObject(hdc, OBJ_BITMAP);
	DeleteDC(hdc);
 
//	gpPicture->Release(); // 这里不能释放gpPicture,否则返回的hRet是野指针数据
 
	return hRet;
}

Bash读取某一行某一列

打印第11行:
sed -n "11, 1p" /tmp/tmp.txt
或者
awk 'NR == 11 {print}' /tmp/tmp.txt

打印第3列:
awk '{print $3;}' /tmp/tmp.txt

打印总行数:
awk 'END {print NR}' /tmp/tmp.txt

MFC CScrollBar拖动完后总跑到零位置

原因是

  1. 要处理SB_ENDSCROLL事件。
  2. 一定要在适当的地方GetScrollPos或SetScrollPos。

正确示例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
void SampleDlg::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
	int iMin = 0, iMax = 0;
	pScrollBar->GetScrollRange(&iMin, &iMax);
 
	// nPos = pScrollBar->GetScrollPos(); // 此处这句话一定不能有
 
	switch (nSBCode)
	{
	case SB_THUMBTRACK:
		break;
	case SB_LINELEFT:
		nPos = pScrollBar->GetScrollPos(); // 此处这句话一定要有
		nPos--;
		if (nPos < (UINT)iMin)
			nPos = 0;
		break;
	case SB_LINERIGHT:
		nPos = pScrollBar->GetScrollPos(); // 此处这句话一定要有
		nPos++;
		if (nPos >= (UINT)iMax)
			nPos = iMax - 1;
		break;
	case SB_ENDSCROLL:
		nPos = pScrollBar->GetScrollPos(); // 此处这句话一定要有
		break;
	default:
		break;
	}
 
	pScrollBar->SetScrollPos(nPos, 1); // 此处这句话也一定要有
 
	// Todo real work with nPos.
 
	CDialogEx::OnHScroll(nSBCode, nPos, pScrollBar);
}

error C4839: 作为可变参数函数的参数的非标准用法

报错语句为:

1
	_stprintf_s(filepath, _T("%s\\%s"), curpath, CA2T(iniFilePath));

改为如下就不报错了:

1
2
	CString iniFilePathT = CA2T(iniFilePath);
	_stprintf_s(filepath, _T("%s\\%s"), curpath, (LPCTSTR)iniFilePathT);

targetSdkVersion未安装应用程式

发布后在Android 6.1的手机上安装不了,显示“未安装应用程序”,检查源码发现build.gradle文件中

1
2
3
4
    defaultConfig {
        minSdkVersion 14
	targetSdkVersion 27
    }

于是,把targetSdkVersion改为23,而发布release版时,Signature Versions只选V1(Jar Signature)。
再将生成的apk包在安卓6.1手机上装,顺利安装成功。

HLSL显示贴图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
float4x4 worldViewProj : WorldViewProjection;
 
struct VS_INPUT
{
	float3 pos : POSITION;
	float2 tex : TEXCOORD0;
};
 
struct VS_OUTPUT
{
	float4 pos : POSITION;
	float2 tex : TEXCOORD0;  
};
 
VS_OUTPUT mainVS(VS_INPUT input)
{
	VS_OUTPUT vsOut;	
	vsOut.pos = mul(float4(input.pos, 1), worldViewProj);
	vsOut.tex = input.tex;
//	vsOut.tex.xy = vsOut.pos.zw;
	return vsOut;
}
 
texture tex0;
 
sampler2D sample0 = 
sampler_state
{
	Texture = <tex0>;
/*	MipFilter = LINEAR;
	MinFilter = LINEAR;
	MagFilter = LINEAR;
 
	AddressU = CLAMP;
	AddressV = CLAMP;
*/
};
 
float4 mainPS(float2 tex : TEXCOORD0) : COLOR
{
	return tex2D(sample0, tex);
//	return tex.x / tex.y;
}
 
technique technique0 {
	pass p0 {
		VertexShader = compile vs_3_0 mainVS();
		PixelShader = compile ps_3_0 mainPS();
	}
}

yv12 to nv21

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
void nv212Yv12(char *nv21, char *yv12, int width, int height)
{
    int frameSize = width * height;
    memcpy(yv12, nv21, frameSize);
    nv21 += frameSize;
    yv12 += frameSize;
    int halfWidth = width / 2;
    int halfHeight = height / 2;
    int quadFrame = halfWidth * halfHeight;
    for (int i = 0; i < halfHeight; i++) {
        for (int j = 0; j < halfWidth; j++) {
            *(yv12 + i * halfWidth + j) = *nv21++;
            *(yv12 + quadFrame + i * halfWidth + j) = *nv21++;
        }
    }
}
 
void yv122Nv21(char *yv12, char *nv21, int width, int height)
{
    int frameSize = width * height;
    memcpy(nv21, yv12, frameSize);
    nv21 += frameSize;
    yv12 += frameSize;
    int halfWidth = width / 2;
    int halfHeight = height / 2;
    int quadFrame = halfWidth * halfHeight;
    for (int i = 0; i < halfHeight; i++) {
        for (int j = 0; j < halfWidth; j++) {
            *nv21++ = *(yv12 + i * halfWidth + j);
            *nv21++ = *(yv12 + quadFrame + i * halfWidth + j);
        }
    }
}

NDK硬解h264

有几点须注意,

  1. 不要让硬解码器自已绘制表面,也就是AMediaCodec_configure传入的surface应设为空。否则运行时间长了,会出现“weak global reference table overflow”的崩机错误。
  2. 我之前文章里也说过了,不要静态链编libmediandk.so,老的安卓机上没有这个库,要动态检测加载,详细过程见之后代码。
  3. AMediaCodec_dequeueInputBuffer不是每一次都返回成功,如果失败了而丢弃h264数据帧,则最终的播放效果就时不时出现花屏,正确处理见之后代码。
  4. 硬解码器解出的数据默认可能是NV12格式也可能是YV12格式,不同的手机不一样,预先配置解码器的"color-format"为19,也没用。为了与ffmpeg解出的数据一致为YU12格式,统一地我们自已转。

以下是源码,摘选自EuhatRtsp开源软件,经历过长时间拷机运行没问题。其网址是:http://euhat.com/rtsp.html


DecoderHard.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#pragma once
 
#include "DecodeOp.h"
 
class AMediaCodec;
 
class EuhatDecoderHard : public EuhatDecoderBase
{
    int updateSpsAndPps();
 
    int spsChanged_;
    int ppsChanged_;
    char *sps_;
    char *pps_;
    int width_;
    int height_;
    int oriHeight_;
    int colorFormat_;
    int stride_;
    int sliceHeight_;
    int cropTop_;
    int cropBottom_;
    int cropLeft_;
    int cropRight_;
    int isCodecInited_;
    void *surface_;
    int surfaceChanged_;
 
public:
    EuhatDecoderHard();
    virtual ~EuhatDecoderHard();
 
    virtual int init(EuhatDecoderCallback callback, void *context);
    virtual int fini();
    virtual int updateSps(const char *sps);
    virtual int updatePps(const char *pps);
    virtual int updateWH(int width, int height);
    virtual int updateSurface(void *surface);
    virtual int decode(char *frame, int frameLen);
 
    static int canWork();
 
    AMediaCodec *mediaCodec_;
};

Read more

数据结构好文推荐

红黑树演示
https://sandbox.runjs.cn/show/2nngvn8w
 
有哪些最新的机器学习可视化工具?
https://www.toutiao.com/a6567983574299967757/
 
NDK-FFmpeg视频解码
http://www.imooc.com/article/80058
 
RSA加密原理
http://blog.jobbole.com/42699/

https://github.com/fredericgermain/LeakTracer