<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>XCoderLiu's Blog</title>
    <description>吾生也有涯，而知也无涯！</description>
    <link>https://xcoderliu.github.io/</link>
    <atom:link href="https://xcoderliu.github.io/feed.xml" rel="self" type="application/rss+xml"/>
    <pubDate>Tue, 12 Jul 2022 05:24:03 +0000</pubDate>
    <lastBuildDate>Tue, 12 Jul 2022 05:24:03 +0000</lastBuildDate>
    <generator>Jekyll v3.9.2</generator>
    
      <item>
        <title>Mac编译opencv 环境搭建</title>
        <description>&lt;h3 id=&quot;安装-opencv&quot;&gt;安装 opencv&lt;/h3&gt;

&lt;p&gt;首先安装 homebrew 运行：&lt;/p&gt;

&lt;p&gt;Homebrew 3.5.4&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;brew install opencv
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;配置-xcode&quot;&gt;配置 xcode&lt;/h3&gt;

&lt;p&gt;xcode 13.4.1&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Library Search Paths 添加:
/opt/homebrew/opt/opencv/lib

Header Search Paths 添加:
/opt/homebrew/opt/opencv/include/**

library 中添加 /opt/homebrew/opt/opencv/lib 下全部的 .a 文件
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;openCV lib 可能遇到签名问题我们可以在 Xcode Signing &amp;amp; Capabilities -&amp;gt; Hardened Runtime 勾选 Disable Library Validation&lt;/p&gt;
</description>
        <pubDate>Fri, 08 Jul 2022 04:35:00 +0000</pubDate>
        <link>https://xcoderliu.github.io/2022/07/Mac%E7%BC%96%E8%AF%91-opencv-%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA/</link>
        <guid isPermaLink="true">https://xcoderliu.github.io/2022/07/Mac%E7%BC%96%E8%AF%91-opencv-%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA/</guid>
        
        <category>opencv</category>
        
        
      </item>
    
      <item>
        <title>Flutter InheritedWidget</title>
        <description>&lt;h3 id=&quot;赘述&quot;&gt;赘述&lt;/h3&gt;

&lt;p&gt;学习 Flutter 之后有两个很重要的概念，StatefulWidget 和 StatelessWidget，其中 Stateful 其实指的就是需要要数据的 UI 并且会根据数据进行调整，也是程序开发中最为常见的状态，比较数据驱动 UI 显示。Stateless 是不需要记录状态的 Widget，一个静态的不需要根据数据做调整的 UI。而今天讲到另一个类型的 Widget，Inherited Widget 他并不能以大多数面向对象编程语言中的继承来理解。&lt;/p&gt;

&lt;h3 id=&quot;inheritedwidget-解决了什么&quot;&gt;InheritedWidget 解决了什么？&lt;/h3&gt;

&lt;p&gt;当我们写好了一个父 StatefulWidget 的容器时，我们的子 Widget 很可能需要根据父视图的一些数据做出不同的渲染，这时候我们需要通过 InheritedWidget 将我们的数据传递到下层 Widget。总而言之，InheritedWidget 允许在 widget 树中有效地向下传播（和共享）信息。&lt;/p&gt;

&lt;h3 id=&quot;实现--用法&quot;&gt;实现 &amp;amp; 用法&lt;/h3&gt;

&lt;p&gt;InheritedWidget 通常需要名为 of 的静态方法，让所以有子 Widget 通过包含的 context 获得最近的 InheritedWidget 实例。updateShouldNotify 当我们的数据变化是否需要通知到子 Widget。子 Widget 中用法 ：InheritedWidget.of(context).xxx 。需要注意的是许多 InheritedWidget 是经常在整个 app 生命周期中保持不变的，这本身没什么问题，实际上我们定义的使用用 final 关键字，仅仅以为着这个值不可被重新赋值，但并不是说内部不可以改变。你可以定义一个 final 的 service 。举个例子，它可以是你封装好的数据库service、一个 web API 的代理、或者 assets 的 provider 等等。这些 service 可以包含自己内部的改变，所以这些子控件在可以通过 of 访问到 service 这样一个内部是动态的 object。&lt;/p&gt;

</description>
        <pubDate>Sat, 30 May 2020 11:45:00 +0000</pubDate>
        <link>https://xcoderliu.github.io/2020/05/Flutter-InheritedWidget/</link>
        <guid isPermaLink="true">https://xcoderliu.github.io/2020/05/Flutter-InheritedWidget/</guid>
        
        <category>Flutter</category>
        
        
      </item>
    
      <item>
        <title>Dart语法初窥</title>
        <description>&lt;p&gt;今天稍微体验了下 &lt;strong&gt;Dart&lt;/strong&gt; 毕竟2020年了，&lt;strong&gt;Flutter&lt;/strong&gt; 终于迎来了第一个 stable 版本。我学习 &lt;strong&gt;Flutter&lt;/strong&gt; 还是喜欢从语言层面慢慢展开学习，贴一下 &lt;a href=&quot;https://dart.dev/guides&quot;&gt;dart 官方学习网站&lt;/a&gt;。
不在这儿详细讲每个语法细节，只讲我对比 swift c++ 或者 objective-c 的语法中看到的一些好玩的东西。&lt;/p&gt;

&lt;h2 id=&quot;mixins&quot;&gt;Mixins&lt;/h2&gt;
&lt;h3 id=&quot;mixins-with-official&quot;&gt;Mixins with official&lt;/h3&gt;

&lt;p&gt;首先说说这个，它是我看介绍里面一眼没法看懂的东西。&lt;/p&gt;

&lt;p&gt;Look at this!&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;// Mixins are a way of reusing a class’s code in multiple class hierarchies.
// To use a mixin, use the with keyword followed by one or more mixin names. 
// The following example shows two classes that use mixins:

class Musician extends Performer with Musical {
  // ···
}

class Maestro extends Person
    with Musical, Aggressive, Demented {
  Maestro(String maestroName) {
    name = maestroName;
    canConduct = true;
  }
}

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;这是官方的详细介绍，解释的第一行用来解决 dart 多继承，实际上大多数语言都是单继承，我见到的除了 c++ 。看到这儿我脑海里扑面而来的感觉是这是 swift 和 objective-c 的 Protocol 么？&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;// To implement a mixin, create a class that extends Object and declares no constructors. 
// Unless you want your mixin to be usable as a regular class, use the mixin keyword instead of class. 
// For example:

mixin Musical {
  bool canPlayPiano = false;
  bool canCompose = false;
  bool canConduct = false;

  void entertainMe() {
    if (canPlayPiano) {
      print('Playing piano');
    } else if (canConduct) {
      print('Waving hands');
    } else {
      print('Humming to self');
    }
  }
}

// To specify that only certain types can use the mixin — for example, 
// so your mixin can invoke a method that it doesn’t define — use on to specify the required superclass:

mixin MusicalPerformer on Musician {
  // ···
}

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;That is all! WFT???&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/common/wtf.jpg&quot; alt=&quot;wtf&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;talk-is-cheap-show-me-your-code&quot;&gt;Talk is cheap, show me your code!&lt;/h3&gt;

&lt;p&gt;1.手写我写了 &lt;strong&gt;ABCDEF&lt;/strong&gt; 这几个类，然后我开始乱用继承了哈哈哈，然后我摸索出这个玩意儿真的很像 &lt;strong&gt;协议&lt;/strong&gt;，但是使用它需要具备一定&lt;a href=&quot;https://github.com/dart-lang/language/blob/master/accepted/2.1/super-mixins/feature-specification.md#dart-2-mixin-declarations&quot;&gt;条件&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Derived from a class declaration.&lt;/li&gt;
  &lt;li&gt;Applied to a superclass to create a new class.&lt;/li&gt;
  &lt;li&gt;May be derived from class with super-class, then application must be on class implementing super-class interface.&lt;/li&gt;
  &lt;li&gt;May have super-invocations if the mixin class has a super-class.&lt;/li&gt;
  &lt;li&gt;Cannot have generative constructors.&lt;/li&gt;
  &lt;li&gt;Mixin application forwards some constructors.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;补充一下 mixin 关键字的只能继承自 object 不能由别的类派生，这个 change log 好像不包含这条。看到没有构造函数，然后可以用超类的方法中实现，invoke 当前类，我觉得这好像稍微比协议更多了点玩意儿：&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;B&lt;/strong&gt; 继承自 &lt;strong&gt;A&lt;/strong&gt;， &lt;strong&gt;C&lt;/strong&gt; 继承自 &lt;strong&gt;B&lt;/strong&gt;, &lt;strong&gt;E&lt;/strong&gt;,&lt;strong&gt;F&lt;/strong&gt; 我写作 mixin 类型，然后 class C extends B with F 这样编辑器会报错。&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/dart/mixinError.png&quot; alt=&quot;error&quot; /&gt;&lt;/p&gt;

&lt;p&gt;为啥呢？ mixin on 好像就是一个协议建立在另一个协议的基础上，实现的人必须要实现 on 的协议，我尝试了下两种方式编译器都可以通过：&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;C&lt;/strong&gt; 自己实现 &lt;strong&gt;E&lt;/strong&gt;:&lt;/li&gt;
&lt;/ol&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;class A {
  bool a = true;
}

class B extends A {
  bool b = true;
}

class C extends B with E, F {
  bool c = true;
}

class D {
  bool d = true;
}

mixin E {
  bool e = true;
}

mixin F on E {
  bool f = true;
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;2.父类 &lt;strong&gt;B&lt;/strong&gt; 实现 &lt;strong&gt;E&lt;/strong&gt;:&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;class A {
  bool a = true;
}

class B extends A with E {
  bool b = true;
}

class C extends B with F {
  bool c = true;
}

class D {
  bool d = true;
}

mixin E {
  bool e = true;
}

mixin F on E {
  bool f = true;
}

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;各位看官到这儿，想必大家内心有一种懵懂的想法，大家就各自想吧。另外 把 E 和 F 的 mixin 改成 class 这样他们就可以有构造函数可以构建实例了。&lt;/p&gt;

&lt;h2 id=&quot;spread-operator-&quot;&gt;Spread operator (…)&lt;/h2&gt;

&lt;p&gt;…这个操作符可以用来表示一个列表全部元素:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;var list = [1, 2, 3];
var list2 = [0, ...list];
assert(list2.length == 4);
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;如果 list 可能为空我们还可以加个 &lt;strong&gt;？&lt;/strong&gt; （swift 的味道，香）:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;var list;
var list2 = [0, ...?list];
assert(list2.length == 1);
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;collection-if&quot;&gt;Collection if&lt;/h2&gt;

&lt;p&gt;你可以在集合类型中添加 &lt;strong&gt;if&lt;/strong&gt; 条件判断：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;var nav = [
  'Home',
  'Furniture',
  'Plants',
  if (promoActive) 'Outlet'
];
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;是不是很神奇，这样写 UI 就很嗨了，比如你要写个翻页的页面，但是最后一页可以不要加上 &lt;strong&gt;Next&lt;/strong&gt; button：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Widget build(BuildContext context) {
  return Column(children: [
    Text(mainText),
    if (page != pages.last)
      FlatButton(child: Text('Next')),
  ]);
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;collection-for&quot;&gt;Collection for&lt;/h2&gt;

&lt;p&gt;你可以在集合类型中添加 &lt;strong&gt;for&lt;/strong&gt; 遍历添加：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Widget build(BuildContext context) {
  return Column(children: [
    Text(mainText),
    for (var section in sections)
      HeadingAction(section.heading),
  ]);
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;end&quot;&gt;End&lt;/h2&gt;

&lt;p&gt;All this ,我看到 &lt;strong&gt;Dart&lt;/strong&gt; 之所以是 &lt;strong&gt;Dart&lt;/strong&gt;， 首先是因为它是 &lt;strong&gt;Flutter&lt;/strong&gt; 的官方语言吧。&lt;/p&gt;
</description>
        <pubDate>Tue, 12 May 2020 09:48:00 +0000</pubDate>
        <link>https://xcoderliu.github.io/2020/05/Dart%E8%AF%AD%E6%B3%95%E5%88%9D%E7%AA%A5/</link>
        <guid isPermaLink="true">https://xcoderliu.github.io/2020/05/Dart%E8%AF%AD%E6%B3%95%E5%88%9D%E7%AA%A5/</guid>
        
        <category>Flutter</category>
        
        
      </item>
    
      <item>
        <title>Yosemites dark mode</title>
        <description>&lt;h3 id=&quot;检查dark模式的代码如下&quot;&gt;检查Dark模式的代码如下：&lt;/h3&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;NSDictionary *dict = [[NSUserDefaults standardUserDefaults] persistentDomainForName:NSGlobalDomain];
id style = [dict objectForKey:@&quot;AppleInterfaceStyle&quot;];
BOOL darkModeOn = ( style &amp;amp;&amp;amp; [style isKindOfClass:[NSString class]] &amp;amp;&amp;amp; NSOrderedSame == [style caseInsensitiveCompare:@&quot;dark&quot;]);

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;设置监听-darkmode-改变&quot;&gt;设置监听 darkmode 改变&lt;/h3&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;[[NSDistributedNotificationCenter defaultCenter] addObserver:self selector:@selector(darkModeChanged:) name:@&quot;AppleInterfaceThemeChangedNotification&quot; object:nil];

-(void)darkModeChanged:(NSNotification *)notif {
    NSLog(@&quot;Dark mode changed&quot;);
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

</description>
        <pubDate>Tue, 21 Aug 2018 00:00:00 +0000</pubDate>
        <link>https://xcoderliu.github.io/2018/08/dorkDockYosemites/</link>
        <guid isPermaLink="true">https://xcoderliu.github.io/2018/08/dorkDockYosemites/</guid>
        
        <category>OSX</category>
        
        
      </item>
    
      <item>
        <title>C++ 内存布局&amp;虚函数</title>
        <description>&lt;h3 id=&quot;关于c的内存布局&quot;&gt;关于c++的内存布局&lt;/h3&gt;
&lt;p&gt;比如我们写这样一个简单的代码&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;class Parent
{
public:
	Parent(){}
	~Parent(){}
	void Say() { cout &amp;lt;&amp;lt; &quot;Parent&quot; &amp;lt;&amp;lt; endl; }
protected:
	
private:
};

class Son:public Parent
{
public:
	Son() {}
	~Son() {}
	void Say() { cout &amp;lt;&amp;lt; &quot;Son&quot; &amp;lt;&amp;lt; endl; }
protected:

private:
};
int main()
{
	Parent *p = new Son;
	p-&amp;gt;Say();
	getchar();
    return 0;
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;很显然这个程序的输出是 &lt;strong&gt;Parent&lt;/strong&gt; 因为我们用基类的指针指向超类的时候，因为是普通成员函数所以父类指针只能访问到父类的存储空间。这时候我们调用 &lt;strong&gt;Say&lt;/strong&gt; 方法就只会调用父类的方法。&lt;/p&gt;

&lt;h3 id=&quot;虚函数&quot;&gt;虚函数&lt;/h3&gt;

&lt;p&gt;然后我们只要在稍微改动下代码&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;class Parent
{
public:
	Parent(){}
	~Parent(){}
	virtual void Say() { cout &amp;lt;&amp;lt; &quot;Parent&quot; &amp;lt;&amp;lt; endl; }
protected:
	
private:
};
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;结果就完全不一样了，因为加上了虚函数的关键字后，只要子类进行重载不管写没写 &lt;strong&gt;virtual&lt;/strong&gt; 关键字都是会对应在续表中生成虚函数。所以这时候即使是父类指针指向子类的实例，通过虚函数重载虚函数表将被覆盖的话调用的依然是子类的方法，输出就是 &lt;strong&gt;Son&lt;/strong&gt; 。&lt;/p&gt;
</description>
        <pubDate>Tue, 21 Aug 2018 00:00:00 +0000</pubDate>
        <link>https://xcoderliu.github.io/2018/08/c++mem/</link>
        <guid isPermaLink="true">https://xcoderliu.github.io/2018/08/c++mem/</guid>
        
        <category>C++</category>
        
        
      </item>
    
      <item>
        <title>算法学习-初级探索</title>
        <description>&lt;h2 id=&quot;学习目的&quot;&gt;学习目的&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;学习算法&lt;/strong&gt;其实不是说算法存在一个唯一的标准答案，而是面试或者工作中我们我们能够针对具体业务能够提供更合理的解决方案。&lt;/p&gt;

&lt;h2 id=&quot;如何针对业务选择算法举个&quot;&gt;如何针对业务选择算法（举个🌰）&lt;/h2&gt;

&lt;h3 id=&quot;针对一个数组排序的情况&quot;&gt;针对一个数组排序的情况&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;如果数组含有大量重复的元素 – 推荐三路快排&lt;/li&gt;
  &lt;li&gt;如果数组近乎有序 – 推荐插入排序&lt;/li&gt;
  &lt;li&gt;如果数组取值范围有限 – 推荐计数排序&lt;/li&gt;
  &lt;li&gt;如果需要稳定或者存储结构是链表 – 推荐归并排序&lt;/li&gt;
  &lt;li&gt;如果可以使用的内存空间较小 – 考虑外排序&lt;/li&gt;
&lt;/ul&gt;

</description>
        <pubDate>Wed, 01 Aug 2018 08:40:00 +0000</pubDate>
        <link>https://xcoderliu.github.io/2018/08/%E7%AE%97%E6%B3%95%E5%AD%A6%E4%B9%A0-%E7%AC%94%E8%AE%B0/</link>
        <guid isPermaLink="true">https://xcoderliu.github.io/2018/08/%E7%AE%97%E6%B3%95%E5%AD%A6%E4%B9%A0-%E7%AC%94%E8%AE%B0/</guid>
        
        <category>algorithm</category>
        
        
      </item>
    
      <item>
        <title>Ubuntu Install Boost</title>
        <description>&lt;p&gt;1.安装依赖库：&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;apt-get &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;mpi-default-dev　　#安装mpi库  
&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;apt-get &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;libicu-dev　　　　　#支持正则表达式的UNICODE字符集   
&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;apt-get &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;python-dev　　　　　#需要python的话  
&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;apt-get &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;libbz2-dev　　　　　#如果编译出现错误：bzlib.h: No such file or directory  
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;2.下载Boost库并解压&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;./bootstrap.sh
&lt;span class=&quot;nb&quot;&gt;sudo&lt;/span&gt; ./b2
&lt;span class=&quot;nb&quot;&gt;sudo&lt;/span&gt; ./b2 &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;3.测试&lt;/p&gt;

&lt;div class=&quot;language-c++ highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cp&quot;&gt;#include&amp;lt;iostream&amp;gt;
#include&amp;lt;boost/bind.hpp&amp;gt;
&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;namespace&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;namespace&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;boost&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;fun&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;){&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;}&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(){&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;cout&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;boost&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bind&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fun&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;endl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

</description>
        <pubDate>Sun, 25 Mar 2018 00:51:00 +0000</pubDate>
        <link>https://xcoderliu.github.io/2018/03/Ubuntu%E5%AE%89%E8%A3%85boost/</link>
        <guid isPermaLink="true">https://xcoderliu.github.io/2018/03/Ubuntu%E5%AE%89%E8%A3%85boost/</guid>
        
        <category>Server</category>
        
        
      </item>
    
      <item>
        <title>Mac OS X 开启原生自带虚拟内存盘（Ramdisk）</title>
        <description>&lt;p&gt;虚拟内存盘是通过软件将一部分内存（RAM）模拟为硬盘来使用的一种技术。&lt;/p&gt;

&lt;p&gt;由于内存有高达数 GB 每秒的速度，模拟成硬盘在适当情景下使用，会极大的增强系统性能，并且起到保护硬盘和隐私的作用。&lt;/p&gt;

&lt;p&gt;Mac OS X 是 Unix 类型系统，原生就支持用命令行创建Ramdisk。所以可以省去了买 iRamdisk、tmpDisk 这类鸡肋软件。&lt;/p&gt;

&lt;p&gt;如果细心按照本教程一步步的模仿，那么很容易就可以创建一个开机自动创建的 Ramdisk&lt;/p&gt;

&lt;p&gt;1、 打开 Dashbord，找到实用工具中的脚本编辑器（10.10中叫这个名字）。输入以下内容：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;do shell script &quot;
if ! test -e /Volumes/\&quot;Ramdisk\&quot; ; then
diskutil erasevolume HFS+ \&quot;RamDisk\&quot; `hdiutil attach -nomount ram://2097152`
fi
mkdir /Volumes/Ramdisk/TempDownloads
mkdir -p /Volumes/Ramdisk/Library/Developer/Xcode/DerivedData
mkdir -p /Volumes/Ramdisk/Library/Developer/CoreSimulator/Devices
mkdir -p /Volumes/Ramdisk/Library/Caches/Google
mkdir -p /Volumes/Ramdisk/Library/Caches/com.apple.Safari/fsCachedData
mkdir -p /Volumes/Ramdisk/Library/Caches/com.netease.163music
mkdir -p /Volumes/Ramdisk/Library/Caches/Firefox
&quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;可以创建一个1GB 的虚拟内存盘。其中数字2097152 =1024&lt;em&gt;1024&lt;/em&gt;1GB&lt;em&gt;2（最后的那个2是必须乘上的）。实际创建出来的不是1GB 整数，而是1.07GB 左右。可能是系统的对磁盘大小计算方法问题，但是这个公式肯定是正确的。（如果是2GB 那么就是1024&lt;/em&gt;1024&lt;em&gt;2GB&lt;/em&gt;2=4194304，把这个数字体换上即可。）&lt;/p&gt;

&lt;p&gt;2、 将上述脚本保存为 app 格式，即可成为一个可执行文件。&lt;/p&gt;

&lt;p&gt;3、 打开系统与偏好设置-用户和群组-登录项选项卡&lt;/p&gt;

&lt;p&gt;4、 点击左下角小锁头解锁后按下加号加入刚刚我们编写的脚本程序，
即可实现脚本的开机自动启动，并且创建一个1GB 的虚拟磁盘。&lt;/p&gt;

&lt;p&gt;这个脚本除了创建磁盘，还在磁盘中创建了几个文件夹：&lt;/p&gt;

&lt;p&gt;根目录有TempDownloads和一个 Library 文件夹。
Library 文件夹下有 Caches 文件夹和 Developer 文件夹。（Caches 放 Chrome 和 Safari 的浏览器缓存，Developer 放 Xcode 的临时编译空间文件）
5、 接下来把浏览器缓存和 Xcode 临时编译空间在内存盘上创建一个替身（就是一个软链接，类似 Windows 的快捷方式）。&lt;/p&gt;

&lt;p&gt;首先确保退出 Safari、Chrome、Xcode 这三个程序，然后再终端输入（一条一条输入）&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;rm -rf ~/Library/Caches/Google
rm -rf ~/Library/Caches/com.apple.Safari
rm -rf ~/Library/Developer/Xcode/DerivedData
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;上面三条命令删除了磁盘中三个程序的临时缓存文件夹，放心，100%安全。只要你打开程序，这三个文件夹还会自动生成。&lt;/p&gt;

&lt;p&gt;6、 在执行下面三个命令前，必须把我们的脚本执行起来，在桌面上或者 finder 中能打开我们的内存盘，看到里面有我们创建的目录，才能正常执行下面的程序：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;ln -s /Volumes/Ramdisk/Library/Caches/Google ~/Library/Caches/Google
ln -s /Volumes/Ramdisk/Library/Caches/com.apple.Safari~/Library/Caches/com.apple.Safari
ln -s /Volumes/Ramdisk/Library/Developer/Xcode/ ~/Library/Developer/Xcode/DerivedData
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;7、 这样，打开 Safari 或者 Chrome或者 Xcode 依次测试，就可以看到在内存盘的相关目录中产生了他们的缓存文件。同时如果我们打开这几个程序原本的目录，会发现他们会自动跳转到内存盘的相应目录下，在 SSD 中不再会产生任何垃圾。于此大功告成。以上所有命令都只需要输入一次，以后开机自动可用。&lt;/p&gt;

&lt;p&gt;同时建议关闭休眠模式，Mac 默认的休眠模式是3，是一种混合休眠模式，在合盖保存工作到内存时，同时为了防止断电工作丢失，也保存一份到本地磁盘。对于笔记本来说，这个模式实属多余，电量不足还是选择关机吧。模式3意味着将要把内存中的工作保存到磁盘的休眠镜像文件中，这又会造成大量读写。&lt;/p&gt;

&lt;p&gt;为了兼容起见，建议直接把模式改为0，就是只启用睡眠模式。（关闭盖子工作只保存到内存），关闭休眠：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;sudo pmset -a hibernatemode 0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;为了防止该文件再重启后重新生成。（不建议删除，没必要）&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;sudo touch /private/var/vm/sleepimage 
sudo chmod 000 /private/var/vm/sleepimage
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;其他相关命令：
pmset -g | grep hibernate （查看当前的hibernate模式）
ls -lh /private/var/vm/sleepimage （查看sleepimage文件大小）
今后如果需要打开hibernate模式，再将该值设为默认的就可以了：&lt;/p&gt;

&lt;p&gt;sudo pmset -a hibernatemode 3 （设置hibernatemode为默认值3）
sudo rm /private/var/vm/sleepimage
几个小提示和说明：&lt;/p&gt;

&lt;p&gt;Xcode 编译程序会生成大量的中间文件，一般数百兆甚至更多，放到内存盘中很有必要。&lt;/p&gt;

&lt;p&gt;如果要还原三个程序的原本缓存位置，只需再次输入那三条 rm -rf 开头的命令即可。&lt;/p&gt;

&lt;p&gt;如果内存盘满了，可以手动清理，或者重启后自动清空。&lt;/p&gt;

&lt;p&gt;不建议把整个~/Library/Caches/都链接到内存盘中，因为有一个 com.apple.helped文件夹，只要使用 Xcode 之类的程序，会自动下载帮助文档多达数百兆。每次清理后都会重新下载生成，会严重消耗资源。倒不如让他在硬盘里躺着。&lt;/p&gt;

&lt;p&gt;除了这三个程序，其他程序的缓存一般都很小，用不着管他。清除了反而影响程序的启动加载时间。只需要每隔半个月用 cleanMyMac 清理一次即可。（放过那个com.apple.helped，那个文件只要大的不是很夸张多达数 GB，就半年清理一次吧）。&lt;/p&gt;

&lt;p&gt;链接到 Ramdisk 的目录，清理软件是不会帮忙清理的，只能手动清理，或者重启自动丢失。&lt;/p&gt;
</description>
        <pubDate>Wed, 26 Apr 2017 00:26:00 +0000</pubDate>
        <link>https://xcoderliu.github.io/2017/04/macRamDisk/</link>
        <guid isPermaLink="true">https://xcoderliu.github.io/2017/04/macRamDisk/</guid>
        
        <category>OSX</category>
        
        
      </item>
    
      <item>
        <title>ffmpegMetalPlayer(OSX)教程一</title>
        <description>&lt;h3 id=&quot;简介&quot;&gt;简介&lt;/h3&gt;
&lt;p&gt;这一份教程是关于如何使用最新的 FFmpeg 3.2.4 进行音视频的编解码,以及如何使用 metal 对解码之后的帧数据进行渲染. 感觉现在的 ffmpeg 教程都是基于 2.x 的所以就自己鼓捣了一下,希望和大家一起讨论交流共同进步. 本教程的 &lt;a href=&quot;https://github.com/xcoderliu/FFmpegMetalPlayer&quot;&gt;github 源码&lt;/a&gt; (运行环境 OSX)也会跟随本教程持续更新.因为作者有全职工作所以不能保证更新进度望大家理解. 本教程也参考了 &lt;a href=&quot;https://github.com/kolyvan/kxmovie&quot;&gt;kxMovie&lt;/a&gt; 感谢作者.&lt;/p&gt;

&lt;h3 id=&quot;音视频基础介绍&quot;&gt;音视频基础介绍&lt;/h3&gt;
&lt;p&gt;首先,大家需要有一定的基础知识,对于音视频其实大家都知道所谓的视频就是一帧一帧的图片组合而成.随着时间正确的渲染出图片就能播放一个视频. 同样的音频就是在正确的时间播放出对应的声音.在对的时间贴上对的图对的声音就能播放完整的电影了.&lt;/p&gt;

&lt;h3 id=&quot;ffmpeg-介绍&quot;&gt;FFmpeg 介绍&lt;/h3&gt;
&lt;p&gt;FFmpeg是一个自由软件，可以运行音频和视频多种格式的录影、转换、流功能[1]，包含了libavcodec——这是一个用于多个项目中音频和视频的解码器库，以及libavformat——一个音频与视频格式转换库。
“FFmpeg”这个单词中的“FF”指的是“Fast Forward”[2]。有些新手写信给“FFmpeg”的项目负责人，询问FF是不是代表“Fast Free”或者“Fast Fourier”等意思，“FFmpeg”的项目负责人回信说：“Just for the record, the original meaning of “FF” in FFmpeg is “Fast Forward”…”
这个项目最初是由Fabrice Bellard发起的，而现在是由Michael Niedermayer在进行维护。许多FFmpeg的开发者同时也是MPlayer项目的成员，FFmpeg在MPlayer项目中是被设计为服务器版本进行开发。
2011年3月13日，FFmpeg部分开发人士决定另组Libav，同时制定了一套关于项目继续发展和维护的规则。&lt;/p&gt;

&lt;h4 id=&quot;ffmpeg-组件&quot;&gt;FFmpeg 组件&lt;/h4&gt;
&lt;ul&gt;
  &lt;li&gt;ffmpeg——一个命令行工具，用来对视频文件转换格式，也支持对电视卡即时编码&lt;/li&gt;
  &lt;li&gt;ffserver——一个HTTP多媒体即时广播流服务器，支持时光平移&lt;/li&gt;
  &lt;li&gt;ffplay——一个简单的播放器，基于SDL与FFmpeg库&lt;/li&gt;
  &lt;li&gt;libavcodec——包含全部FFmpeg音频/视频编解码库&lt;/li&gt;
  &lt;li&gt;libavformat——包含demuxers和muxer库&lt;/li&gt;
  &lt;li&gt;libavutil——包含一些工具库&lt;/li&gt;
  &lt;li&gt;libpostproc——对于视频做前处理的库&lt;/li&gt;
  &lt;li&gt;libswscale——对于视频作缩放的库&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;利用-ffmpeg-视频解码&quot;&gt;利用 FFmpeg 视频解码&lt;/h3&gt;
&lt;p&gt;在项目中我们可以创建一个负责音视频解码的类,命名为 xxDecoder.mm ,在初始化函数中调用 &lt;strong&gt;av_register_all();&lt;/strong&gt; 方法初始化 FFmpeg,然后开始对视频进行编解码.&lt;/p&gt;

&lt;h4 id=&quot;检测音视频文件是否可以解码&quot;&gt;检测音视频文件是否可以解码&lt;/h4&gt;
&lt;p&gt;一些比较简单的工作在本教程中我就省略了,比如创建一个 NSOpenPanel 实例去选取音视频文件.拿到文件之后我们需要对文件的传入路径做一下分析看它是不是一个本地文件,因为 FFmpeg 也支持多媒体即使广流服务器.(本教程截止 2017.02.28 播放器仅支持本地播放 实际上还没解码音频😅) 假如是流媒体文件我们需要调用 &lt;strong&gt;avformat_network_init();&lt;/strong&gt; .
首先我们需要创建一个 &lt;strong&gt;AVFormatContext&lt;/strong&gt; 实例,这个实例对我们来说是非常重要的需要作为我们解码类的一个成员确定可以打开文件之后进行成员变量的赋值.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;//创建 AVFormatContext 实例
    AVFormatContext *formatCtx = NULL;
    //容错回调
    if (_interruptCallback) {
        
        formatCtx = avformat_alloc_context();
        if (!formatCtx)
            return lzmMediaErrorOpenFile;
        
        AVIOInterruptCB cb = {interrupt_callback, (__bridge void *)(self)};
        formatCtx-&amp;gt;interrupt_callback = cb;
    }
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;以上代码就是创建一个 AVFormatContext 实例然后创建了一个回调假如解码出现错误能够及时回调做出相应的处理.&lt;/p&gt;

&lt;p&gt;接下来使用 FFmpeg 接口打开传入的文件路径, &lt;strong&gt;avformat_open_input&lt;/strong&gt; 没有出错的话,我们还需要检查是否能打开音视频流.一切 OK 就可以保存这样一个 AVFormatContext 实例.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;    //打开文件获得错误码
    int err_code = avformat_open_input(&amp;amp;formatCtx, [path cStringUsingEncoding:NSUTF8StringEncoding], NULL, NULL);
    //出现错误
    if (err_code != 0) {
        
        if (formatCtx)
            avformat_free_context(formatCtx);
        
        char* buf[1024];
        av_strerror(err_code, (char*)buf, 1024);
        printf(&quot;Couldn't open file %s: %d(%s)&quot;, [path cStringUsingEncoding: NSUTF8StringEncoding], err_code, (char*)buf);
        
        return lzmMediaErrorOpenFile;
    }
    
	//获取音视频流
    if (avformat_find_stream_info(formatCtx, NULL) &amp;lt; 0) {
        
        avformat_close_input(&amp;amp;formatCtx);
        return lzmMediaErrorStreamInfoNotFound;
    }
    
    //打印音视频的具体信息
    av_dump_format(formatCtx, 0, [path.lastPathComponent cStringUsingEncoding: NSUTF8StringEncoding], 0);
    
    _formatCtx = formatCtx;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;以上代码基本上就是确定了视频文件的有效性,以及文件可被解码.
接下来就是具体解码视频的过程,FFmpeg 解码是根据时间来解码出当时的视频图片,所以首先我们自己写一个定时器,然后再定时器中不断调用解码的函数并传入需要解码的时间.
FFmpeg 3.x 解码是用 &lt;strong&gt;avcodec_send_packet&lt;/strong&gt; 和 &lt;strong&gt;avcodec_receive_frame&lt;/strong&gt;.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;- (NSArray *) decodeFrames: (CGFloat) minDuration
{
    if (_videoStream == -1 &amp;amp;&amp;amp;
        _audioStream == -1)
        return nil;
    
    NSMutableArray *result = [NSMutableArray array];
    
    AVPacket packet;//Usually single video frame or several complete audio frames.
    
    CGFloat decodedDuration = 0;
    
    BOOL finished = NO;
    
    while (!finished) {
        
        if (av_read_frame(_formatCtx, &amp;amp;packet) &amp;lt; 0) {
            _isEOF = YES;
            break;
        }
        
        if (packet.stream_index ==_videoStream) {
            
            int errorcode = avcodec_send_packet(_videoCodecCtx, &amp;amp;packet);
            if (errorcode != 0) {
                break;
            }
            errorcode = avcodec_receive_frame(_videoCodecCtx, _videoFrame);
            if (errorcode != 0) {
                break;
            }
            
            lzmVideoFrame *frame = [self handleVideoFrame];
            if (frame) {
                
                [result addObject:frame];
                
                _position = frame.position;
                decodedDuration += frame.duration;
                if (decodedDuration &amp;gt; minDuration)
                    finished = YES;
            }  
        }     
    return result;
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;以上代码中最关键的是:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; avcodec_send_packet(_videoCodecCtx, &amp;amp;packet);
 avcodec_receive_frame(_videoCodecCtx, _videoFrame
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;这段代码能够将 _videoFrame 赋值.然后经过我们的处理函数 &lt;strong&gt;handleVideoFrame&lt;/strong&gt; 将 FFmpeg 的 frame 数据转换成我们的自定义 frame 数据.&lt;/p&gt;

</description>
        <pubDate>Tue, 28 Feb 2017 12:14:00 +0000</pubDate>
        <link>https://xcoderliu.github.io/2017/02/ffmpegMetalPlayer/</link>
        <guid isPermaLink="true">https://xcoderliu.github.io/2017/02/ffmpegMetalPlayer/</guid>
        
        <category>OSX</category>
        
        
      </item>
    
      <item>
        <title>Shell 编程实践</title>
        <description>&lt;h3 id=&quot;子文件夹&quot;&gt;子文件夹&lt;/h3&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;subFolders=`find $parentFolder -type d -maxdepth 1 -mindepth 1`
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;进度条&quot;&gt;进度条&lt;/h3&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;function ProgressBar {
# Process data
let _progress=(${1}*100/${2}*100)/100
let _done=(${_progress}*4)/10
let _left=40-$_done
# Build progressbar string lengths
_fill=$(printf &quot;%${_done}s&quot;)
_empty=$(printf &quot;%${_left}s&quot;)

printf &quot;\rProgress : [${_fill// /#}${_empty// /-}] ${_progress}%%&quot;

}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;shell-实战脚本打包&quot;&gt;shell 实战脚本打包&lt;/h3&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;projectPath=/Users/liuzhimin/Dropbox/Personal?Code/Project
thearchviePath=/Users/liuzhimin/Desktop
ipaPath=/Users/liuzhimin/Desktop
projectname=PackageProject
resourcefolder=res_dev
version=$1

cd $projectPath

######copy Dev file######
echo &quot;😀  😀  😀  i will start for development package!&quot;
echo &quot;***************** copy Dev public file start *****************&quot;

cp -rf $projectPath/$resourcefolder/AppIcon.appiconset $projectPath/ProjectClient/Images.xcassets

cp -rf $projectPath/$resourcefolder/InfoPlist.strings/*.lproj $projectPath/ProjectClient/

cp -rf $projectPath/$resourcefolder/Localizable.strings/*.lproj $projectPath/Resources/

cp -rf $projectPath/$resourcefolder/Multiversion  $projectPath/ProjectClient/Images.xcassets

cp -rf $projectPath/$resourcefolder/ProjectClient-InfoDev.plist  $projectPath/ProjectClient/ProjectClient-Info.plist

cp -rf $projectPath/$resourcefolder/configDev.xml  $projectPath/ProjectClient/config.xml

cp -rf $projectPath/$resourcefolder/ClientMgrCfgDev.xml  $projectPath/ProjectClient/meetingMgrCfg.xml

echo &quot;***************** copy Dev over *****************&quot;


######start Dev bulild######
echo &quot;***************** start clean Dev workspace *****************&quot;

xcodebuild clean

rm -rf $thearchviePath/ProjectApp.xcarchive

rm -rf $thearchviePath/ProjectDev.xcarchive

rm -rf $thearchviePath/ProjectIntranet.xcarchive

rm -rf $ipaPath/Project_for_iOS_${version}_test.ipa

rm -rf $ipaPath/Project_for_iOS_${version}_appstore.ipa

rm -rf $ipaPath/Project_for_iOS_${version}_appstore_test.ipa

xcodebuild -project $projectname.xcodeproj -scheme $projectname -configuration Release clean

echo &quot;***************** clean Dev workspace over *****************&quot;

echo &quot;***************** start build Dev workspace *****************&quot;

xcodebuild -project $projectname.xcodeproj -scheme $projectname -configuration Release

echo &quot;***************** build Dev workspace over *****************&quot;

echo &quot;***************** start export Dev archive *****************&quot;

xcodebuild -project $projectname.xcodeproj -scheme $projectname archive -archivePath $thearchviePath/ProjectDev.xcarchive

echo &quot;***************** export Dev archive over *****************&quot;

echo &quot;***************** start export Dev ipa app *****************&quot;

xcodebuild -exportArchive -archivePath $thearchviePath/ProjectDev.xcarchive -exportPath $ipaPath -exportOptionsPlist projectDev.plist

mv $ipaPath/ProjectClient.ipa $ipaPath/Project_for_iOS_ ${version}_test.ipa

echo &quot;***************** export Dev ipa over *****************&quot;


###### Intranet test package ######
echo &quot;😂  😂  😂  now Intranet test package!&quot;
cp -rf $projectPath/$resourcefolder/configIntranet.xml  $projectPath/ProjectClient/config.xml

cp -rf $projectPath/$resourcefolder/meetingMgrCfgIntranet.xml  $projectPath/ProjectClient/meetingMgrCfg.xml

#xcodebuild -project $projectname.xcodeproj -scheme $projectname -configuration Release

xcodebuild -project $projectname.xcodeproj -scheme $projectname archive -archivePath $thearchviePath/ProjectIntranet.xcarchive

xcodebuild -exportArchive -archivePath $thearchviePath/ProjectDev.xcarchive -exportPath $ipaPath -exportOptionsPlist projectDev.plist

mv $ipaPath/ProjectClient.ipa $ipaPath/Project_for_iOS_${version}_Intranet_test.ipa

######copy App file######
echo &quot;😂  😂  😂  then App &amp;amp; APP test package!&quot;
echo &quot;***************** copy App public file start *****************&quot;

cp -rf $projectPath/$resourcefolder/configApp.xml  $projectPath/ProjectClient/config.xml

cp -rf $projectPath/$resourcefolder/meetingMgrCfgApp.xml  $projectPath/ProjectClient/meetingMgrCfg.xml

cp -rf $projectPath/$resourcefolder/ProjectClient-InfoApp.plist  $projectPath/ProjectClient/ProjectClient-Info.plist

echo &quot;***************** copy App over *****************&quot;

echo &quot;***************** start build App workspace *****************&quot;

#xcodebuild -project $projectname.xcodeproj -scheme $projectname -configuration Release

echo &quot;***************** build App workspace over *****************&quot;

echo &quot;***************** start export App archive *****************&quot;

xcodebuild -project $projectname.xcodeproj -scheme $projectname archive -archivePath $thearchviePath/ProjectApp.xcarchive

echo &quot;***************** export App archive over *****************&quot;

echo &quot;***************** start export App ipa app *****************&quot;

xcodebuild -exportArchive -archivePath $thearchviePath/ProjectDev.xcarchive -exportPath $ipaPath -exportOptionsPlist projectRelease.plist

mv $ipaPath/ProjectClient.ipa $ipaPath/Project_for_iOS_${version}_appstore.ipa

xcodebuild -exportArchive -archivePath $thearchviePath/ProjectDev.xcarchive -exportPath $ipaPath -exportOptionsPlist projectDev.plist

mv $ipaPath/ProjectClient.ipa $ipaPath/Project_for_iOS_${version}_appstore_test.ipa

echo &quot;***************** export App ipa over *****************&quot;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;shell-实战脚本分析xcode崩溃日志&quot;&gt;shell 实战脚本分析xcode崩溃日志&lt;/h3&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;shortVersion=3.10.5
longVersion=03.10.5.0
logDirPath=&quot;/Users/liuzhimin/Library/Developer/Xcode/Products/com.inpor.Projectcloudios/${shortVersion}?(${longVersion})/Crashes/AppStore/&quot;
outPutFile=&quot;/Users/liuzhimin/Desktop/CrashLog/CrashAnalyse.log&quot;

#进度条函数
function ProgressBar {
    # Process data
    let _progress=(${1}*100/${2}*100)/100
    let _done=(${_progress}*4)/10
    let _left=40-$_done
    # Build progressbar string lengths
    _fill=$(printf &quot;%${_done}s&quot;)
    _empty=$(printf &quot;%${_left}s&quot;)
    printf &quot;\r日志分析进度 : [${_fill// /#}${_empty// /-}] ${_progress}%%&quot;
}

#数组是否包含函数
function array_containsSubString () {
    local seeking=$1; shift
    local in=1
    for element;
    do
        if [[ &quot;$seeking&quot; == *&quot;$element&quot;* ]]; then
            in=0
            break
        fi
    done
echo $in
}

# 客户端崩溃类型：

declare -a clientCrashArr=(
&quot;Project: -[VNCViewController pinchView:]&quot;
&quot;Project: -[ConfMainViewController chatBtnTap:]&quot;
&quot;AudioToolbox: &quot;
&quot;UIKit:&quot;
&quot;MobileCoreServices&quot;
)

# 系统崩溃类型：

declare -a libCrashArr=(
&quot;libsystem_kernel.dylib: __pthread_kill&quot;
&quot;Project: -[WBPageInnerUIView drawRect:]&quot;
&quot;Project: -[MeetingRoomStateAdaptor UserAudioState:bID:bState:]&quot;
&quot;Project: -[VideoDeviceAdaptor writeVideoSample:buffer:bufferSize:]&quot;
&quot;AGXGLDriver:&quot;
&quot;Project: -[WBPageInnerUIView drawRect:]&quot;
&quot;GLEngine: gliPresentViewES_Exec&quot;
&quot;Project: ff_h264_decode_nal&quot;
&quot;Project: WBASELIB::WMsgQueue&amp;lt;HandlerMsg&amp;gt;::PushMsg(HandlerMsg*, unsigned int*)&quot;
&quot;Project: -[PopoverSheetViewController largeScreen:]&quot;
&quot;Project: std::__1::__tree&amp;lt;std::__1::__value_type&amp;lt;unsigned int, unsigned int&amp;gt;, std::__1::__map_value_compare&amp;lt;unsigned int, std::__1::__value_type&amp;lt;unsigned int, unsigned int&amp;gt;, std::__1::less&amp;lt;unsigned int&amp;gt;, true&amp;gt;, std::__1::allocator&amp;lt;std::__1::__value_type&amp;lt;unsigned int, unsigned int&amp;gt; &amp;gt; &amp;gt;::__node_insert_unique(std::__1::__tree_node&amp;lt;std::__1::__value_type&amp;lt;unsigned int, unsigned int&amp;gt;, void*&amp;gt;*)&quot;
&quot;Project: -[VideoCapture prepareWithWidth:andHeight:andFps:]&quot;
&quot;-[AVCtrl pauseRecvAllAudio:]&quot;
&quot;WNET_NETWORK::CSockWorkThread::ThreadProcEx()&quot;
&quot;IMGSGX554GLDriver&quot;
&quot;AGXMetalA10&quot;
&quot;[WhiteBoardViewController updateWBAccessMode]&quot;
&quot;[MultiWhiteBoardAdaptor setAccessMode:]&quot;
)




cd ${logDirPath}
echo &quot;📂 打开日志文件夹 进行扫描&quot;

crashFoderPaths=`find ./ -type d -maxdepth 1 -mindepth 1`
rm -rf $outPutFile
echo &quot;🚫 remove old analyse log&quot;
sleep 0.5s

touch $outPutFile
echo &quot;📃 创建新的日志准备写入&quot;
sleep 0.5s

#崩溃的类型个数
crashKindCounts=`find ./ -type d -maxdepth 1 -mindepth 1 | wc -l`

#总的崩溃个数
allcrashCounts=0

for crashfolderPath in $crashFoderPaths
do
    #进入同一类崩溃统计的文件夹
    crashFolder=`basename $crashfolderPath`
    cd $crashFolder
    crashLogsCount=`find ./DistributionInfos/all/logs -type f -maxdepth 1 -mindepth 1 | wc -l`
    allcrashCounts=$(($allcrashCounts+$crashLogsCount))
    cd ..
done

#开始读取日志
logStart=0
logEnd=$(($allcrashCounts))

#客户端崩溃个数
clientCrashCounts=0
#服务器端崩溃个数
libCrashCounts=0
#客户端崩溃类型个数
clientCrashKindCounts=0
#服务器端崩溃类型个数
libCrashKindCounts=0
#类型冲突崩溃个数
errorCrashCounts=0
#未知崩溃个数
unknownCrashCounts=0

for crashfolderPath in $crashFoderPaths
do
    #进入同一类崩溃统计的文件夹
    crashFolder=`basename $crashfolderPath`
    cd $crashFolder

    crashName=`cat Info.json | jq '.DefaultName'`
    echo 崩溃名: ${crashName} &amp;gt;&amp;gt; $outPutFile

    crashLogsCount=`find ./DistributionInfos/all/logs -type f -maxdepth 1 -mindepth 1 | wc -l`
    echo 崩溃次数: ${crashLogsCount} &amp;gt;&amp;gt; $outPutFile

    iscrashTop=`cat ./DistributionInfos/all/Info.json | jq '.IsTopCrash'`
    echo 是否排行靠前崩溃: ${iscrashTop} &amp;gt;&amp;gt; $outPutFile

    #客户端崩溃
    isClient=$(array_containsSubString &quot;$crashName&quot; &quot;${clientCrashArr[@]}&quot;)
    isLib=$(array_containsSubString &quot;$crashName&quot; &quot;${libCrashArr[@]}&quot;)

    if test $isClient -eq 0 &amp;amp;&amp;amp; test $isLib -eq 1; then
        clientCrashCounts=$(($clientCrashCounts+$crashLogsCount))
        clientCrashKindCounts=$(($clientCrashKindCounts+1))
        echo 崩溃类型: 客户端崩溃 &amp;gt;&amp;gt; $outPutFile
    fi


    if test $isLib -eq 0 &amp;amp;&amp;amp; test $isClient -eq 1; then
        libCrashCounts=$(($libCrashCounts+$crashLogsCount))
        libCrashKindCounts=$(($libCrashKindCounts+1))
        echo 崩溃类型: 平台崩溃 &amp;gt;&amp;gt; $outPutFile
    fi

    if test $isClient -eq 0 &amp;amp;&amp;amp; test $isLib -eq 0; then
        errorCrashCounts=$(($errorCrashCounts+$crashLogsCount))
        echo 崩溃类型: 类型冲突 &amp;gt;&amp;gt; $outPutFile
    fi


    if test $isLib -eq 1 &amp;amp;&amp;amp; test $isClient -eq 1; then
        unknownCrashCounts=$(($unknownCrashCounts+$crashLogsCount))
        echo 崩溃类型: 未知崩溃 &amp;gt;&amp;gt; $outPutFile
    fi

    echo  &quot;&quot;  &amp;gt;&amp;gt; $outPutFile

    logStart=$(($logStart+$crashLogsCount))
    ProgressBar ${logStart} $logEnd

    cd ..
done

echo

echo 统计结果:
echo 所有崩溃总个数: $allcrashCounts
echo 崩溃类型总个数: $crashKindCounts
echo 统计结果:   &amp;gt;&amp;gt; $outPutFile
echo 所有崩溃总个数: $allcrashCounts   &amp;gt;&amp;gt; $outPutFile
echo 崩溃类型总个数: $crashKindCounts &amp;gt;&amp;gt; $outPutFile
persents=`echo &quot;scale=4; ($clientCrashCounts * 100 / $allcrashCounts )&quot; | bc | awk '{printf &quot;%.4f&quot;, $0}'`
echo 客户端崩溃共 $clientCrashCounts 个，崩溃类型 $clientCrashKindCounts 个，占 $persents %
echo 客户端崩溃 $clientCrashCounts 个，崩溃类型 $clientCrashKindCounts 个，占 $persents %   &amp;gt;&amp;gt; $outPutFile
persents=`echo &quot;scale=4; ($libCrashCounts * 100 / $allcrashCounts )&quot; | bc | awk '{printf &quot;%.4f&quot;, $0}'`
echo 平台崩溃共 $libCrashCounts 个，崩溃类型 $libCrashKindCounts 个，占 $persents %
echo 平台崩溃共 $libCrashCounts 个，崩溃类型 $libCrashKindCounts 个，占 $persents %   &amp;gt;&amp;gt; $outPutFile
persents=`echo &quot;scale=4; ($errorCrashCounts * 100 / $allcrashCounts )&quot; | bc | awk '{printf &quot;%.4f&quot;, $0}'`
echo 冲突崩溃 $errorCrashCounts 个，占 $persents %
echo 冲突崩溃 $errorCrashCounts 个，占 $persents %   &amp;gt;&amp;gt; $outPutFile
persents=`echo &quot;scale=4; ($unknownCrashCounts * 100 / $allcrashCounts )&quot; | bc | awk '{printf &quot;%.4f&quot;, $0}'`
echo 未知崩溃 $unknownCrashCounts 个，占 $persents %
echo 未知崩溃 $unknownCrashCounts 个，占 $persents %   &amp;gt;&amp;gt; $outPutFile

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;shell-实战符号化崩溃日志&quot;&gt;shell 实战符号化崩溃日志&lt;/h3&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;#!/bin/bash

IFS=$'\n'

ARGS=(&quot;$@&quot;)

XCODE_DIR=&quot;/Applications/Xcode.app&quot;
export DEVELOPER_DIR=&quot;${XCODE_DIR}/Contents/Developer&quot;

XCODE_VERSION=$(defaults read /Applications/Xcode.app/Contents/version.plist CFBundleShortVersionString)

if [ ${XCODE_VERSION:0:1} == &quot;6&quot; ]; then
	CRASH=&quot;${XCODE_DIR}/Contents/SharedFrameworks/DTDeviceKitBase.framework/Versions/Current/Resources/symbolicatecrash&quot;
else
	# test work on xcode7-8
	CRASH=&quot;${XCODE_DIR}/Contents/SharedFrameworks/DVTFoundation.framework/Versions/A/Resources/symbolicatecrash&quot;
fi

function checkUUIDAndExec()
{
	LOG_PATH=$1
	APP_PATH=$2

	if [ $(echo &quot;$APP_PATH&quot; | grep &quot;\.app\.dsym&quot;) ]; then
		# Find raw UUID when file is .app.dsym
		APP_UUID=$(dwarfdump --uuid $APP_PATH)
	elif [ $(echo &quot;$APP_PATH&quot; | grep &quot;\.app&quot;) ]; then
		# Find raw UUID when file is .app
		# Find executable file name
		for i in $(ls &quot;$APP_PATH&quot;); do
			if [ $(echo &quot;$i&quot; | grep &quot;\.&quot;) ]; then
				continue
			elif [ $(echo &quot;$i&quot; | grep &quot;PkgInfo&quot;) ]; then
				continue
			elif [ $(echo &quot;$i&quot; | grep &quot;_CodeSignature&quot;) ]; then
				continue
			else
				EXEC_NAME=$i
			fi
		done
		if [ &quot;$EXEC_NAME&quot;x = x ]; then
			echo &quot;App name not found&quot;
		fi
		APP_UUID=$(dwarfdump --uuid &quot;$APP_PATH/$EXEC_NAME&quot;)
	else
		echo &quot;App path $APP_PATH is not valid&quot;
		return
	fi

	# Extract UUID from raw data
	for i in $(echo &quot;$APP_UUID&quot; | grep -Eo &quot;UUID: [0-9a-fA-F\-]+ &quot;); do
		if [[ &quot;$i&quot; = &quot;UUID:&quot; ]]; then
			continue
		else
			# Execute if lowercase UUID is found in crash log
			UUID=$(echo &quot;${i//-/}&quot; | tr 'A-F' 'a-f' | awk '{print $2}')
			if [[ $(grep &quot;$UUID&quot; &quot;$LOG_PATH&quot;) ]]; then
				$CRASH -v $ARGS
				break
			else
				echo &quot;UUID is not matched&quot;
			fi
		fi
	done
}

checkUUIDAndExec $1 $2

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
</description>
        <pubDate>Mon, 20 Feb 2017 00:14:00 +0000</pubDate>
        <link>https://xcoderliu.github.io/2017/02/Shell/</link>
        <guid isPermaLink="true">https://xcoderliu.github.io/2017/02/Shell/</guid>
        
        <category>shell</category>
        
        
      </item>
    
  </channel>
</rss>
