精华内容
下载资源
问答
  • read命令
    千次阅读
    2019-03-28 16:32:09

     

    1. Read的一些选项

     Read可以带有-a, -d, -e, -n, -p, -r, -t, 和 -s八个选项。

    -a :将内容读入到数值中

    echo -n "Input muliple values into an array:"
    read -a array
    echo "get ${#array[@]} values in array"

    -d :表示delimiter,即定界符,一般情况下是以IFS为参数的间隔,但是通过-d,我们可以定义一直读到出现执行的字符位置。例如read –d madfds value,读到有m的字符的时候就不在继续向后读,例如输入为 hello m,有效值为“hello”,请注意m前面的空格等会被删除。这种方式可以输入多个字符串,例如定义“.”作为结符号等等。

    -e :只用于互相交互的脚本,它将readline用于收集输入行。读到这几句话不太明白什么意思,先跳过。

    -n :用于限定最多可以有多少字符可以作为有效读入。例如echo –n 4 value1 value2,如果我们试图输入12 34,则只有前面有效的12 3,作为输入,实际上在你输入第4个字符‘3’后,就自动结束输入。这里结果是value为12,value2为3。

    -p :用于给出提示符,在前面的例子中我们使用了echo –n “…“来给出提示符,可以使用read –p ‘… my promt?’value的方式只需一个语句来表示。

    -r :在参数输入中,我们可以使用’/’表示没有输入完,换行继续输入,如果我们需要行最后的’/’作为有效的字符,可以通过-r来进行。此外在输入字符中,我们希望/n这类特殊字符生效,也应采用-r选项。

    -s :对于一些特殊的符号,例如箭头号,不将他们在terminal上打印,例如read –s key,我们按光标,在回车之后,如果我们要求显示,即echo,光标向上,如果不使用-s,在输入的时候,输入处显示^[[A,即在terminal上 打印,之后如果要求echo,光标会上移。

    -t :用于表示等待输入的时间,单位为秒,等待时间超过,将继续执行后面的脚本,注意不作为null输入,参数将保留原有的值

    2. Read的相关实例

    a. 拼接文件

    #将afile文件中的前三行与bfile中的前四行拼接在一起
    while read -u3 i && read -u4 j;do
    echo $i $j
    done 3<afile 4<bfile

    b. 输入不在终端显示

    read -p "Input passwd:" -s Passwd
    echo $Passwd

    c. 限时输入,否则退出

    #延迟五秒,没有输入将自动退出
    read -p "Input a number:" -t 5 Number

    d. 读取限定字符

    #从输入中取5个字符
    read -p "Input a word:" -n 5 Word

    e. 等待输出q退出

    #输入,直到输入q,将自动退出
    read -dp -p "Input some words end with q:" word


    #####################################
    http://blog.sina.com.cn/s/blog_4077692e0100r7ct.html

    read命令 -n(不换行) -p(提示语句) -n(字符个数) -t(等待时间) -s(不回显)

     

    1、基本读取

    read命令接收标准输入(键盘)的输入,或其他文件描述符的输入(后面在说)。得到输入后,read命令将数据放入一个标准变量中。下面是read命令

    的最简单形式::

    #!/bin/bash

    echo -n "Enter your name:" //参数-n的作用是不换行,echo默认是换行

    read name //从键盘输入

    echo "hello $name,welcome to my program" //显示信息

    exit 0 //退出shell程序。

    //********************************

    由于read命令提供了-p参数,允许在read命令行中直接指定一个提示。

    所以上面的脚本可以简写成下面的脚本::

    #!/bin/bash

    read -p "Enter your name:" name

    echo "hello $name, welcome to my program"

    exit 0

    在上面read后面的变量只有name一个,也可以有多个,这时如果输入多个数据,则第一个数据给第一个变量,第二个数据给第二个变量,如果输入数据个数过多,则最后所有的值都给第一个变量。如果太少输入不会结束。

    //*****************************************

    在read命令行中也可以不指定变量.如果不指定变量,那么read命令会将接收到的数据放置在环境变量REPLY中。

    例如::

    read -p "Enter a number"

    环境变量REPLY中包含输入的所有数据,可以像使用其他变量一样在shell脚本中使用环境变量REPLY.

    2、计时输入.

    使用read命令存在着潜在危险。脚本很可能会停下来一直等待用户的输入。如果无论是否输入数据脚本都必须继续执行,那么可以使用-t选项指定一个计时器。

    -t选项指定read命令等待输入的秒数。当计时满时,read命令返回一个非零退出状态;

    #!/bin/bash

    if read -t 5 -p "please enter your name:" name

    then

    echo "hello $name ,welcome to my script"

    else

    echo "sorry,too slow"

    fi

    exit 0

    除了输入时间计时,还可以设置read命令计数输入的字符。当输入的字符数目达到预定数目时,自动退出,并将输入的数据赋值给变量。

    #!/bin/bash

    read -n1 -p "Do you want to continue [Y/N]?" answer

    case $answer in

    Y | y)

    echo "fine ,continue";;

    N | n)

    echo "ok,good bye";;

    *)

    echo "error choice";;

    esac

    exit 0

    该例子使用了-n选项,后接数值1,指示read命令只要接受到一个字符就退出。只要按下一个字符进行回答,read命令立即

    接受输入并将其传给变量。无需按回车键。

     

    3、默读(输入不显示在监视器上)

    有时会需要脚本用户输入,但不希望输入的数据显示在监视器上。典型的例子就是输入密码,当然还有很多其他需要隐藏的数据。

    -s选项能够使read命令中输入的数据不显示在监视器上(实际上,数据是显示的,只是read命令将文本颜色设置成与背景相同的颜色)。

    #!/bin/bash

    read -s -p "Enter your password:" pass

    echo "your password is $pass"

    exit 0

    4、读文件

    最后,还可以使用read命令读取Linux系统上的文件。

    每次调用read命令都会读取文件中的"一行"文本。当文件没有可读的行时,read命令将以非零状态退出。

    读取文件的关键是如何将文本中的数据传送给read命令。

    最常用的方法是对文件使用cat命令并通过管道将结果直接传送给包含read命令的while命令

    例子::

    #!/bin/bash

    count=1 //赋值语句,不加空格

    cat test | while read line //cat 命令的输出作为read命令的输入,read读到的值放在line中

    do

    echo "Line $count:$line"

    count=$[ $count + 1 ] //注意中括号中的空格。

    done

    echo "finish"

    exit 0

    read 命令:

    -p  提示语句

    -n 字符个数

    -t  等待时间

    -d 输入分界

     

    Read 来获取变量,是通过屏幕中等待用户输入的,如果是用read命令从已知的变量中来获取值要 如何操作呢

    比如:input_ips=’127.127.127.10-127.127.127.14’,通过read命令分别读取到start_ip,end_ip两变量中。

     

    方法一:

    Input_ips=’ 127.127.127.10-127.127.127.14’

    read  START_IP  END_IP << (echo $input_ips|awk –F’-’ ‘{print$1,print$2}’)

    Echo –e “START_IP =$start_ip;END_IP=$end_cip”

    START_IP=127.127.127.10 ;END_IP=127.127.127.14

    方法二:

    Input_ips=’ 127.127.127.10-127.127.127.14’

    Read start_ip end_ip << -EOF

    `echo $input_ips|awk –F’-’ ‘{print $1,$2}’`

    EOF                                                                                                                                 

    Echo –e “START_IP =$start_ip;END_IP=$end_cip”

    START_IP=127.127.127.10 ;END_IP=127.127.127.14

    (1) Read  #从标准输入读取一行并赋值给特定变量REPLY

    root@#read

    Hello

    root@#echo $REPLY

    Hello

    (2) Read name  #从标准输入读取输入并赋值给变量name

    root@#read  name

    Jerry

    root@#echo $name

    Jerry

    (3)read var1 var2

    root@#read  Name1  Name2

    Jerry  Gao

    root@#echo “name1:$Name1 name2:$n=Name2”

    name1:Jerry  name2:Gao

    (4)read –p “text”  #打印提示’text’,等待输入,并将输入存储在REPLY中

    (5)read –p “text”  var  #打印提示’text’,等待输入,并将输入存储在var中

    更多相关内容
  • Matlab中readtable用法

    万次阅读 2021-06-21 14:29:46
    readtable是基于文件创建表。 语法 T = readtable(filename) T = readtable(filename,opts) T = readtable(___,Name,Value)

    目录

    语法

    说明

    示例

    基于文本文件创建表

    忽略标题并填充缺失值

    基于文本文件创建表,无列标题

    基于文本文件创建格式表

    从文本文件读取外语日期

    基于包含行名称的电子表格创建表

    从电子表格中读取特定范围的数据

    检测并使用针对文本文件的导入选项

    检测并使用针对电子表格文件的导入选项

    读取包含任意变量名称的表格数据

    从文件中读取十六进制和二进制数字


            readtable是基于文件创建表。

    语法

    T = readtable(filename)
    T = readtable(filename,opts)
    T = readtable(___,Name,Value)

    说明

    T= readtable(filename) 通过从文件中读取列向数据来创建表。

              readtable 基于文件的扩展名确定文件格式:

    • .txt.dat 或 .csv(适用于带分隔符的文本文件)

    • .xls.xlsb.xlsm.xlsx.xltm.xltx 或 .ods(适用于电子表格文件)

            readtable 为该文件中的每列在 T 中创建一个变量并从文件的第一行中读取变量名称。默认情况下,readtable 会根据在输入文件的每列中检测到的数据值来创建具有适当数据类型的变量。

    T = readtable(filename,opts) 使用导入选项 opts 创建表。

    T = readtable(___,Name,Value) 基于文件创建一个表,并通过一个或多个名称-值对组参数指定其他选项。例如,可以指定 readtable 是将文件的第一行读取为变量名称还是数据。

            要为数据设置特定的导入选项,可以使用 opts 对象,也可以指定名称-值对组。当指定除 opts 之外的名称-值对组时,readtable 仅支持下列名称-值对组:

    • 文本和电子表格参数 - ReadVariableNamesReadRowNames

    • 仅文本参数 - DateLocaleEncoding

    • 仅电子表格参数 - SheetUseExcel

    示例

    基于文本文件创建表

           加载文件 myCsvTable.dat 并在文本编辑器中预览其内容。屏幕截图如下所示。请注意,该文件包含逗号分隔的列向数据。

    filename = 'myCsvTable.dat';

           基于逗号分隔的文本文件创建表。生成的表 T 为文件中的每一列包含一个变量,readtable 将文件第一行中的项视为变量名称。

    T = readtable(filename)
    
    
    T=5×6 table
          LastName      Gender    Age    Height    Weight    Smoker
        ____________    ______    ___    ______    ______    ______
    
        {'Smith'   }    {'M'}     38       71       176        1   
        {'Johnson' }    {'M'}     43       69       163        0   
        {'Williams'}    {'F'}     38       64       131        0   
        {'Jones'   }    {'F'}     40       67       133        0   
        {'Brown'   }    {'F'}     49       64       119        0   
    

    忽略标题并填充缺失值

           从 R2020a 开始,readtable函数读取输入文件的方式就好像它自动对该文件调用 detectImportOptions 函数一样。它可以检测数据类型,丢弃多余的标题行,并填充缺失值。

           例如,在文本编辑器中预览文件 headersAndMissing.txt。该文件有一个列名行,还有一个标题行。最后两行有空缺,前面的各行包含数据值。

            基于该文件创建一个表。readtable 函数将丢弃标题。此外,它还用适当的缺失值来填补空缺 - 对于数值变量,用 NaN 值;对于文本,用空字符向量。

    T = readtable('headersAndMissing.txt')
    
    
    T=5×6 table
         LastName        Gender      Age    Height    Weight    Smoker
        ___________    __________    ___    ______    ______    ______
    
        {'Wu'     }    {'M'     }     38      71       176        1   
        {'Johnson'}    {'M'     }     43      69       163        0   
        {'Sanchez'}    {'F'     }     38      64       131        0   
        {'Brown'  }    {'F'     }    NaN      67       133        0   
        {'Picard' }    {0x0 char}    NaN      64       119        0   

            要还原以前的版本的默认行为,请指定 'Format','auto' 名称-值对组参数。readtable 会将标题作为数据读取,因此,它会将所有表变量均转换为文本。

    T = readtable('headersAndMissing.txt','Format','auto')
    
    
    T=6×6 table
         LastName        Gender         Age        Height     Weight       Smoker   
        ___________    __________    __________    _______    _______    ___________
    
        {'string' }    {'string'}    {'int'   }    {'int'}    {'int'}    {'boolean'}
        {'Wu'     }    {'M'     }    {'38'    }    {'71' }    {'176'}    {'1'      }
        {'Johnson'}    {'M'     }    {'43'    }    {'69' }    {'163'}    {'0'      }
        {'Sanchez'}    {'F'     }    {'38'    }    {'64' }    {'131'}    {'0'      }
        {'Brown'  }    {'F'     }    {0x0 char}    {'67' }    {'133'}    {'0'      }
        {'Picard' }    {0x0 char}    {0x0 char}    {'64' }    {'119'}    {'0'      }

           有关详细信息,请参阅本页的“兼容性注意事项”部分。

    基于文本文件创建表,无列标题

           在文本编辑器中预览文件 mySpaceDelimTable.txt。屏幕截图如下所示。请注意,该文件包含空格分隔的列向数据。

           基于以空格分隔的文本文件创建一个表。由于文件的第一行不包含可检测到的列名称,因此 readtable 函数将分配默认的变量名称 Var1 到 Var5

    T = readtable('mySpaceDelimTable.txt')
    
    
    T=3×5 table
        Var1     Var2    Var3     Var4       Var5   
        _____    ____    ____    ______    _________
    
        {'M'}     45      45     {'NY'}    {'true' }
        {'F'}     41      32     {'CA'}    {'false'}
        {'M'}     40      34     {'MA'}    {'false'}
    

    基于文本文件创建格式表

           加载文件 myCsvTable.dat 并在文本编辑器中预览其内容。屏幕截图如下所示。请注意,该文件包含逗号分隔的列向数据。

    filename = 'myCsvTable.dat';

            基于逗号分隔的文本文件创建表。将前两列导入为字符向量,将第三列导入为 uint32,将接下来的两列导入为双精度浮点数。将最后一列的条目导入为字符向量。

    T = readtable(filename,'Format','%s%s%u%f%f%s')
    
    
    T=5×6 table
          LastName      Gender    Age    Height    Weight    Smoker
        ____________    ______    ___    ______    ______    ______
    
        {'Smith'   }    {'M'}     38       71       176      {'1'} 
        {'Johnson' }    {'M'}     43       69       163      {'0'} 
        {'Williams'}    {'F'}     38       64       131      {'0'} 
        {'Jones'   }    {'F'}     40       67       133      {'0'} 
        {'Brown'   }    {'F'}     49       64       119      {'0'} 
    

           对于字符向量元胞数组,转换设定符为 %s,对于 double,转换设定符为 %f,对于 uint32,转换设定符为 %u

    从文本文件读取外语日期

          从文件读取以德语表示的日期,再用以英语表示的日期形式,将其添加到一个表中。

          在文本编辑器中预览文件 german_dates.txt。屏幕截图如下所示。请注意,第一列值包含德语的日期,第二列和第三列是数值。

          使用 readtable 读取示例文件。对于日期,转换设定符为 %D,对于浮点值,转换设定符为 %f。使用 FileEncoding 名称-值对组参数指定文件编码。使用 DateLocale 名称-值对组参数指定日期格式和区域设置。

    T = readtable('german_dates.txt',...
        'Format','%{dd MMMM yyyy}D %f %f',...
        'FileEncoding','ISO-8859-15',...
        'DateLocale','de_DE')
    
    
    T=3×3 table
              Var1          Var2    Var3 
        ________________    ____    _____
    
         01 January 2014    20.2    100.5
        01 February 2014    21.6    102.7
           01 March 2014    20.7     99.8
    

    基于包含行名称的电子表格创建表

           基于包含第一行的变量名称和第一列的行名称的电子表格创建表。

    T = readtable('patients.xls','ReadRowNames',true);

           显示表的前五行和前四个变量。

    T(1:5,1:4)
    
    
    ans=5×4 table
                      Gender      Age              Location               Height
                    __________    ___    _____________________________    ______
    
        Smith       {'Male'  }    38     {'County General Hospital'  }      71  
        Johnson     {'Male'  }    43     {'VA Hospital'              }      69  
        Williams    {'Female'}    38     {'St. Mary's Medical Center'}      64  
        Jones       {'Female'}    40     {'VA Hospital'              }      67  
        Brown       {'Female'}    49     {'County General Hospital'  }      64  
    

           查看该表的 DimensionNames 属性。

    T.Properties.DimensionNames
    
    ans = 1x2 cell
        {'LastName'}    {'Variables'}
    

        'LastName' 是电子表格第一行第一列中的名称。

    从电子表格中读取特定范围的数据

           使用电子表格 patients.xls 的指定区域中的数据创建表。使用 C2 和 E6 两个对角之间的 5×3 矩形区域内的数据。不要将该区域的第一行用作变量名称。

    T = readtable('patients.xls',...
        'Range','C2:E6',...
        'ReadVariableNames',false)
    
    
    T = 
    
        Var1               Var2                Var3
        ____    ___________________________    ____
    
        38      'County General Hospital'      71  
        43      'VA Hospital'                  69  
        38      'St. Mary's Medical Center'    64  
        40      'VA Hospital'                  67  
        49      'County General Hospital'      64  
    

        T 包含默认的变量名称。

    检测并使用针对文本文件的导入选项

           创建导入选项,定制多个变量的数据类型,然后读取数据。根据文本文件创建导入选项对象。

    opts = detectImportOptions('airlinesmall.csv')
    opts = 
      DelimitedTextImportOptions with properties:
    
       Format Properties:
                        Delimiter: {','}
                       Whitespace: '\b\t '
                       LineEnding: {'\n'  '\r'  '\r\n'}
                     CommentStyle: {}
        ConsecutiveDelimitersRule: 'split'
            LeadingDelimitersRule: 'keep'
           TrailingDelimitersRule: 'ignore'
                    EmptyLineRule: 'skip'
                         Encoding: 'ISO-8859-1'
    
       Replacement Properties:
                      MissingRule: 'fill'
                  ImportErrorRule: 'fill'
                 ExtraColumnsRule: 'addvars'
    
       Variable Import Properties: Set types by name using setvartype
                    VariableNames: {'Year', 'Month', 'DayofMonth' ... and 26 more}
                    VariableTypes: {'double', 'double', 'double' ... and 26 more}
            SelectedVariableNames: {'Year', 'Month', 'DayofMonth' ... and 26 more}
                  VariableOptions: Show all 29 VariableOptions 
    	Access VariableOptions sub-properties using setvaropts/getvaropts
               VariableNamingRule: 'modify'
    
       Location Properties:
                        DataLines: [2 Inf]
                VariableNamesLine: 1
                   RowNamesColumn: 0
                VariableUnitsLine: 0
         VariableDescriptionsLine: 0 
    	To display a preview of the table, use preview

             检查变量 TaxiIn 和 TaxiOut 的 Type 属性。

    getvaropts(opts,{'TaxiIn','TaxiOut'})
    
    
    ans = 
      1x2 TextVariableImportOptions array with properties:
    
        Name
        Type
        FillValue
        TreatAsMissing
        QuoteRule
        Prefixes
        Suffixes
        EmptyFieldRule
        WhitespaceRule

             将变量 TaxiIn 和 TaxiOut 的类型更改为 double

     opts = setvartype(opts,{'TaxiIn','TaxiOut'},'double');

             指定要导入和检查的变量的子集。

    opts.SelectedVariableNames = {'TaxiIn','TaxiOut'};

            使用 readtable 函数以及选项对象导入选定的变量。显示表的摘要。

    T = readtable('airlinesmall.csv',opts);
    
    summary(T)
    Variables:
    
        TaxiIn: 123523x1 double
    
            Values:
    
                Min             0      
                Median          5      
                Max             1451   
                NumMissing      37383  
    
        TaxiOut: 123523x1 double
    
            Values:
    
                Min             0      
                Median          13     
                Max             755    
                NumMissing      37364  

    检测并使用针对电子表格文件的导入选项

           检测针对电子表格文件的导入选项,指定要导入的变量,然后读取数据。根据文件创建导入选项对象。

    opts = detectImportOptions('patients.xls')
    
    opts = 
      SpreadsheetImportOptions with properties:
    
       Sheet Properties:
                            Sheet: ''
    
       Replacement Properties:
                      MissingRule: 'fill'
                  ImportErrorRule: 'fill'
    
       Variable Import Properties: Set types by name using setvartype
                    VariableNames: {'LastName', 'Gender', 'Age' ... and 7 more}
                    VariableTypes: {'char', 'char', 'double' ... and 7 more}
            SelectedVariableNames: {'LastName', 'Gender', 'Age' ... and 7 more}
                  VariableOptions: Show all 10 VariableOptions 
    	Access VariableOptions sub-properties using setvaropts/getvaropts
               VariableNamingRule: 'modify'
    
       Range Properties:
                        DataRange: 'A2' (Start Cell)
               VariableNamesRange: 'A1'
                    RowNamesRange: ''
               VariableUnitsRange: ''
        VariableDescriptionsRange: '' 
    	To display a preview of the table, use preview

            修改选项对象以指定要导入的变量。

    opts.SelectedVariableNames = {'Systolic','Diastolic'};

            使用 readtable 以及选项对象导入指定的变量。

    T = readtable('patients.xls',opts);
    
    summary(T)
    Variables:
    
        Systolic: 100x1 double
    
            Values:
    
                Min         109   
                Median      122   
                Max         138   
    
        Diastolic: 100x1 double
    
            Values:
    
                Min           68  
                Median      81.5  
                Max           99  

    读取包含任意变量名称的表格数据

           可以读取表格数据,同时保留包含任何字符的变量名称,包括空格和非 ASCII 字符。首先,创建一个具有任意变量名称的表,并将该表写入文本文件。然后,读回表格数据,同时保留原始变量名称。创建包含任意变量名称的表,并将表格数据写入文件 'sampletable.txt'

    LastName = {'Sanchez';'Johnson';'Li';'Diaz';'Brown'};
    Age = [38;43;38;40;49];
    Smoker = logical([1;0;1;0;1]);
    varNames = {'Last Name','Age','Smoker (1 or 0)'};
    T = table(LastName,Age,Smoker,'VariableNames',varNames)
    
    
    T=5×3 table
         Last Name     Age    Smoker (1 or 0)
        ___________    ___    _______________
    
        {'Sanchez'}    38          true      
        {'Johnson'}    43          false     
        {'Li'     }    38          true      
        {'Diaz'   }    40          false     
        {'Brown'  }    49          true      
    writetable(T,'sampletable.txt')

           使用 readtable 读回表格数据。默认情况下,MATLAB® 将任何包含空格和非 ASCII 字符的变量名称转换为有效的 MATLAB® 标识符。例如,MATLAB® 将变量名称 'Last Name' 转换为 'LastName',将 'Smoker (1 or 0)' 转换为 'Smoker_1or0_'。要在保留变量名称的同时读取表格数据,请将 'VariableNamingRule' 参数设置为 preserve

    T_preserve = readtable('sampletable.txt',"VariableNamingRule","preserve")
    
    
    T_preserve=5×3 table
         Last Name     Age    Smoker (1 or 0)
        ___________    ___    _______________
    
        {'Sanchez'}    38            1       
        {'Johnson'}    43            0       
        {'Li'     }    38            1       
        {'Diaz'   }    40            0       
        {'Brown'  }    49            1       
    

    从文件中读取十六进制和二进制数字

           可以从文件中读取十六进制和二进制数字,并将它们作为数值变量存储在表中。readtable 函数会自动读取分别包含 0x 和 0b 前缀的十六进制和二进制数字。数值使用整数数据类型存储。也可以使用导入选项来读取不带前缀的这些数字。

           在文本编辑器中预览 hexAndBinary.txt 文件。它的一些列包含带前缀的十六进制和二进制数字,还有一列包含不带前缀的这些数字。

           使用 readtable 读取文件。该函数检测具有 0x 和 0b 前缀的数字,并将它们作为整数存储。第三列没有前缀,因此其值被视为文本。

    T = readtable('hexAndBinary.txt')
    
    T=3×4 table
        Var1     Var2      Var3         Var4    
        _____    ____    ________    ___________
    
          255    255     {'C7F9'}    {'Device1'}
          256      4     {'05BF'}    {'Device2'}
        43981    129     {'F00F'}    {'Device3'}
    

            readtable 函数将数值存储在不同整数类(uint16 和 uint8)中,因为 T.Var1 的值需要 8 位以上的存储空间。

    class(T.Var1)
    
    ans = 
    'uint16'
    
    //
    
    class(T.Var2)
    
    ans = 
    'uint8'

          要指定用于存储从十六进制和二进制数字导入的数值的数据类型,请使用 'HexType' 和 'BinaryType' 名称-值对组参数。将值存储为有符号 32 位整数。

    T = readtable('hexAndBinary.txt','HexType','int32','BinaryType','int32');
    class(T.Var1)
    
    ans = 
    'int32'
    
    //
    class(T.Var2)
    
    ans = 
    'int32'

           可以使用导入选项来检测不带前缀的十六进制和二进制数字,并为它们指定存储。为 hexAndBinary.txt 创建一个导入选项对象。

    opts = detectImportOptions('hexAndBinary.txt')
    opts = 
      DelimitedTextImportOptions with properties:
    
       Format Properties:
                        Delimiter: {','}
                       Whitespace: '\b\t '
                       LineEnding: {'\n'  '\r'  '\r\n'}
                     CommentStyle: {}
        ConsecutiveDelimitersRule: 'split'
            LeadingDelimitersRule: 'keep'
           TrailingDelimitersRule: 'ignore'
                    EmptyLineRule: 'skip'
                         Encoding: 'UTF-8'
    
       Replacement Properties:
                      MissingRule: 'fill'
                  ImportErrorRule: 'fill'
                 ExtraColumnsRule: 'addvars'
    
       Variable Import Properties: Set types by name using setvartype
                    VariableNames: {'Var1', 'Var2', 'Var3' ... and 1 more}
                    VariableTypes: {'auto', 'auto', 'char' ... and 1 more}
            SelectedVariableNames: {'Var1', 'Var2', 'Var3' ... and 1 more}
                  VariableOptions: Show all 4 VariableOptions 
    	Access VariableOptions sub-properties using setvaropts/getvaropts
               VariableNamingRule: 'modify'
    
       Location Properties:
                        DataLines: [1 Inf]
                VariableNamesLine: 0
                   RowNamesColumn: 0
                VariableUnitsLine: 0
         VariableDescriptionsLine: 0 
    	To display a preview of the table, use preview

           要指定第三列应作为十六进制值导入,即使缺少前缀也要导入,请使用 setvaropts 函数来修改表中第三个变量的变量类型。将变量类型设置为 int32

    opts = setvaropts(opts,3,'NumberSystem','hex','Type','int32')
    opts = 
      DelimitedTextImportOptions with properties:
    
       Format Properties:
                        Delimiter: {','}
                       Whitespace: '\b\t '
                       LineEnding: {'\n'  '\r'  '\r\n'}
                     CommentStyle: {}
        ConsecutiveDelimitersRule: 'split'
            LeadingDelimitersRule: 'keep'
           TrailingDelimitersRule: 'ignore'
                    EmptyLineRule: 'skip'
                         Encoding: 'UTF-8'
    
       Replacement Properties:
                      MissingRule: 'fill'
                  ImportErrorRule: 'fill'
                 ExtraColumnsRule: 'addvars'
    
       Variable Import Properties: Set types by name using setvartype
                    VariableNames: {'Var1', 'Var2', 'Var3' ... and 1 more}
                    VariableTypes: {'auto', 'auto', 'int32' ... and 1 more}
            SelectedVariableNames: {'Var1', 'Var2', 'Var3' ... and 1 more}
                  VariableOptions: Show all 4 VariableOptions 
    	Access VariableOptions sub-properties using setvaropts/getvaropts
               VariableNamingRule: 'modify'
    
       Location Properties:
                        DataLines: [1 Inf]
                VariableNamesLine: 0
                   RowNamesColumn: 0
                VariableUnitsLine: 0
         VariableDescriptionsLine: 0 
    	To display a preview of the table, use preview
    

          读取文件并将第三列作为数值(而不是文本)导入。

    T = readtable('hexAndBinary.txt',opts)
    
    T=3×4 table
        Var1     Var2    Var3        Var4    
        _____    ____    _____    ___________
    
          255    255     51193    {'Device1'}
          256      4      1471    {'Device2'}
        43981    129     61455    {'Device3'}
    
    展开全文
  • Linux内核中的READ_ONCE和WRITE_ONCE宏

    千次阅读 2020-07-16 09:08:46
    #define __READ_ONCE(x, check) \ ({ \ union { typeof(x) __val; char __c[1]; } __u; \ if (check) \ __read_once_size(&(x), __u.__c, sizeof(x)); \ else \ __read_...

    在Linux内核代码中,经常可以看到读取一个变量时,不是直接读取的,而是需要借助一个叫做READ_ONCE的宏;同样,在写入一个变量的时候,也不是直接赋值的,而是需要借助一个叫做WRITE_ONCE的宏。

    代码分析

    READ_ONCE宏定义如下(代码位于include/linux/compiler.h中):

    #define __READ_ONCE(x, check)						\
    ({									\
    	union { typeof(x) __val; char __c[1]; } __u;			\
    	if (check)							\
    		__read_once_size(&(x), __u.__c, sizeof(x));		\
    	else								\
    		__read_once_size_nocheck(&(x), __u.__c, sizeof(x));	\
    	smp_read_barrier_depends();                                     \
    	__u.__val;							\
    })
    #define READ_ONCE(x) __READ_ONCE(x, 1)

    READ_ONCE宏直接调用了另一个内部定义的宏__READ_ONCE,第二个参数check传的是1。

    在__READ_ONCE宏中其实定义了一个大的表达式,表达式的值是最后一个语句的值。这个表达式中先定义了一个联合体,联合体的第一个组成部分是__val,它的类型就是要读取变量的类型;联合体的第二个组成部分是一个只包含一个元素的字符数组__c,这样定义的话,__c就可以当做这个联合体的指针来使用了。然后,还用这个联合体定义了一个变量__u,这个变量是一个局部变量,因此是定义在栈上的。由于check传的是1,接着将调用__read_once_size函数:

    #define __READ_ONCE_SIZE						\
    ({									\
    	switch (size) {							\
    	case 1: *(__u8 *)res = *(volatile __u8 *)p; break;		\
    	case 2: *(__u16 *)res = *(volatile __u16 *)p; break;		\
    	case 4: *(__u32 *)res = *(volatile __u32 *)p; break;		\
    	case 8: *(__u64 *)res = *(volatile __u64 *)p; break;		\
    	default:							\
    		barrier();						\
    		__builtin_memcpy((void *)res, (const void *)p, size);	\
    		barrier();						\
    	}								\
    })
    
    static __always_inline
    void __read_once_size(const volatile void *p, void *res, int size)
    {
    	__READ_ONCE_SIZE;
    }

    这个函数的函数体是在宏__READ_ONCE_SIZE中定义的,传入的参数是要读取变量的指针,定义的联合体变量的指针,以及要读取变量的大小。在调用__read_once_size函数时,就将要读取变量的指针转换成了指向volatile变量的指针,告诉编译器要读取的这个变量是volatile的。在C语言中,volatile关键字的作用是:

    1. 声明这个变量易变,不要把它当成一个普通的变量,做出错误的优化。
    2. 保证CPU每次都从内存重新读取变量的值,而不是用寄存器中暂存的值。注意,这里说的是寄存器中缓存的值,而不是CPU缓存中存的值。很多英文文档里面都说了Cache,容易让人产生误解。

    __read_once_size函数要完成的操作是将要读取的变量的值拷贝到临时定义的局部联合体变量__u中。如果要读取变量的长度是1、2、4、8字节的时候,直接使用取指针赋值就行了,由于要读取变量的指针已经被转成了volatile的,编译器保证这个操作不会被优化。如果要读取的变量不是上面说的整字节,那么就要用__builtin_memcpy操作进行拷贝了,但前后都需要加上编译器屏障barrier(),这样就可以保证__builtin_memcpy函数调用本身不会被编译器优化掉。

    接下来__READ_ONCE宏调用了smp_read_barrier_depends函数,这个函数是为了解决某些特殊CPU架构下的缓存一致性问题的(主要是Alpha),也就是所谓的数据依赖内存屏障,在绝大多数CPU架构下都没什么用处。

    __READ_ONCE宏中定义的最后一条语句,就是直接返回局部联合体变量__u中的__val部分,也就是返回要读取变量被拷贝好了的值。由于它是这个表达式的最后一个语句,所以__READ_ONCE宏中定义的表达式的值就是这个值,从而保证了要读取值的变量在使用了READ_ONCE宏后能读取到正确的值。

    分析完READ_ONCE宏,那WRITE_ONCE宏就很简单了,基本上就是把READ_ONCE宏要做的事情反过来:

    #define WRITE_ONCE(x, val) \
    ({							\
    	union { typeof(x) __val; char __c[1]; } __u =	\
    		{ .__val = (__force typeof(x)) (val) }; \
    	__write_once_size(&(x), __u.__c, sizeof(x));	\
    	__u.__val;					\
    })

    还是定义了一个联合体变量__u,然后直接将要赋值的值读进来。接着调用了__write_once_size函数:

    static __always_inline void __write_once_size(volatile void *p, void *res, int size)
    {
    	switch (size) {
    	case 1: *(volatile __u8 *)p = *(__u8 *)res; break;
    	case 2: *(volatile __u16 *)p = *(__u16 *)res; break;
    	case 4: *(volatile __u32 *)p = *(__u32 *)res; break;
    	case 8: *(volatile __u64 *)p = *(__u64 *)res; break;
    	default:
    		barrier();
    		__builtin_memcpy((void *)p, (const void *)res, size);
    		barrier();
    	}
    }

    这次换成了把要赋值变量的指针转换成了指向volatile变量的指针。

    WRITE_ONCE宏的最后一条语句还是会返回要赋值的值的,因此也就是说WRITE_ONCE宏是返回要赋值的值的,只不过一般都没什么用。

    为什么要用READ_ONCE和WRITE_ONCE宏

    通常编译器是以函数为单位对代码进行优化编译的,而且编译器在优化的时候会假设被执行的程序是以单线程来执行的。基于这个假设优化出来的汇编代码,很有可能会在多线程执行的过程中出现严重的问题。可以举几个例子:

    1)编译器可以随意优化不相关的内存访问操作,打乱它们的执行次序。

    例如,对于如下代码:

    a[0] = x;
    a[1] = x;

    编译器可能会将其优化成:

    a[1] = x;
    a[0] = x;

    这对单线程的程序来说没有问题,因为变量x的值是不会改变的。但是,对于多线程的程序来说,变量x的值可能会被别的线程改变,如果要保证它们的执行顺序,必须加上READ_ONCE宏:

    a[0] = READ_ONCE(x);
    a[1] = READ_ONCE(x);

    注意,一定要两个语句都用READ_ONCE宏,这样才能保证次序,单独用一个还是没法保证。当然,在两条语句中间插入编译器屏障也可以解决这个问题。

    又或者,比如下面的程序:

    void process_level(void)
    {
    	msg = get_message();
    	flag = true;
    }
    
    void interrupt_handler(void)
    {
    	if (flag)
    		process_message(msg);
    }

    编译器在编译的时候,有可能会把process_level函数优化成:

    void process_level(void)
    {
    	flag = true;
    	msg = get_message();
    }

    因为它发现这两条语句没有任何关系,而且第二条语句比第一条语句执行速度要快,但是它并不知道flag位其实是一个标志位,必须要在获得消息后才能被设置成真。这时只能将process_level函数改成:

    void process_level(void)
    {
    	WRITE_ONCE(msg, get_message());
    	WRITE_ONCE(flag, true);
    }

    2)如果在编译的时候就能确定某些代码不会被执行到那可能会完全把代码删除。

    例如,对于如下的代码:

    while (tmp = a)
    	do_something_with(tmp);

    如果编译的时候,编译器发现变量a的值永远都是0,那么这条语句就会被优化成:

    do { } while (0);

    直接删除,什么都不做。这时候,为了保留一定会按照代码执行,那么必须改写成:

    while (tmp = READ_ONCE(a))
    		do_something_with(tmp);

    还有,对于如下代码:

    a = 0;
    /* 中间代码没有对变量a赋值 */
    ...... 
    a = 0;

    编译器发现,变量a的值一直是0,那后面再对变量a赋值0就是没有必要的,会直接删除掉最后一个赋值。但是,在多线程程序中,有可能另一个线程更改了变量a。为了保证一定赋值,可以用下面的代码:

    WRITE_ONCE(a, 0);
    /* 中间代码没有对变量a赋值 */
    ...... 
    WRITE_ONCE(a, 0);

    还存在许多奇奇怪怪的编译器优化,都可以用READ_ONCE和WRITE_ONCE宏告诉编译器别这么做。

    不过,READ_ONCE和WRITE_ONCE宏只能保证读写操作不被编译器优化掉,造成多线程执行中出问题,但是它并不能干预CPU执行编译出来的程序,也就是不能解决CPU重排序的问题和缓存一致性的问题,这类问题还是需要使用内存屏障来解决。

    而且,由于READ_ONCE和WRITE_ONCE宏的实现原理本身就是借助了C语言的volatile变量,因此如果要读取或者写入的变量本来就是volatile的就不需要再使用这两个宏了。

    READ_ONCE和WRITE_ONCE宏与编译器屏障的关系

    编译器屏障在Linux内核中是通过调用barrier()宏来实现的,其定义如下(代码位于include/linux/compiler-gcc.h中):

    #define barrier() __asm__ __volatile__("": : :"memory")

    所以,其实barrier()宏就是往正常的C语言代码里插入了一条汇编指令。这条指令告诉编译器(上面的汇编指令只对GCC编译器有效,其它编译器有对应的别的方法),不要将这条汇编指令前的内存读写指令优化到这条汇编指令之后,同时也不能将这条汇编指令之后的内存读写指令优化到这条汇编指令之前。但是,对于这条汇编指令之前的内存读写指令,以及之后的内存读写指令,想怎么优化都行,没有任何限制。 

    而READ_ONCE和WRITE_ONCE针对的是读写操作本身,只会影响使用这两个宏的内存访问操作,不能阻止对其它变量的优化操作。

    展开全文
  • FFmpeg使用av_read_frame()方法读取音频流、视频流、字幕流,得到AVPacket数据包。FFmpeg官方提供的samples有使用示例,或者在ffplay.c代码中:打开文件/网络流后,while循环调用av_read_frame()读取帧数据,也就是...

    FFmpeg使用av_read_frame()方法读取音频流、视频流、字幕流,得到AVPacket数据包。FFmpeg官方提供的samples有使用示例,或者在ffplay.c代码中:打开文件/网络流后,while循环调用av_read_frame()读取帧数据,也就是解封装demux过程,直到文件末尾EOF。

    av_read_frame()的调用链如下图所示:

    1、av_read_frame声明

     av_read_frame方法的声明位于libavformat/avformat.h,如下所示:

    /**
     * Return the next frame of a stream.
     * This function returns what is stored in the file, and does not validate
     * that what is there are valid frames for the decoder. It will split what is
     * stored in the file into frames and return one for each call. It will not
     * omit invalid data between valid frames so as to give the decoder the maximum
     * information possible for decoding.
     *
     * On success, the returned packet is reference-counted (pkt->buf is set) and
     * valid indefinitely. The packet must be freed with av_packet_unref() when
     * it is no longer needed. For video, the packet contains exactly one frame.
     * For audio, it contains an integer number of frames if each frame has
     * a known fixed size (e.g. PCM or ADPCM data). If the audio frames have
     * a variable size (e.g. MPEG audio), then it contains one frame.
     *
     * pkt->pts, pkt->dts and pkt->duration are always set to correct
     * values in AVStream.time_base units (and guessed if the format cannot
     * provide them). pkt->pts can be AV_NOPTS_VALUE if the video format
     * has B-frames, so it is better to rely on pkt->dts if you do not
     * decompress the payload.
     *
     * @return 0 if OK, < 0 on error or end of file. On error, pkt will be blank
     *         (as if it came from av_packet_alloc()).
     *
     * @note pkt will be initialized, so it may be uninitialized, but it must not
     *       contain data that needs to be freed.
     */
    int av_read_frame(AVFormatContext *s, AVPacket *pkt);

    中文大意为:该方法返回文件存储的帧数据,但不会为解码器校验帧是否有效。把文件拆分为若干个帧,每次调用返回一帧数据包。

    返回的数据包被引用计数,并且永久有效。如果不再需要该packet包,必须使用av_packet_unref()进行释放。对于视频,每个packet只包含一帧。对于音频,如果是固定大小(比如PCM或ADPCM),返回若干帧;如果是可变大小,它只包含一帧。

    pkt->dts、pkt->pts、pkt->duration使用timebase作为单位,总是被设为准确值。如果视频中存在B帧,pkt->pts可能为AV_NOPTS_VALUE,所以最好使用pkt->dts作为依赖。

    返回0代表成功,小于0代表错误或文件结束。如果是错误,pkt将会为空。

    2、av_read_frame的实现

    av_read_frame()方法主要调用avpriv_packet_list_get()和av_read_frame_internal(),分为无genpts与有genpts两种情况进行读取:

    int av_read_frame(AVFormatContext *s, AVPacket *pkt)
    {
        const int genpts = s->flags & AVFMT_FLAG_GENPTS;
        int eof = 0;
        int ret;
        AVStream *st;
        // 没有设置genpts,直接读取一帧数据
        if (!genpts) {
            ret = s->internal->packet_buffer
                  ? avpriv_packet_list_get(&s->internal->packet_buffer,
                                            &s->internal->packet_buffer_end, pkt)
                  : read_frame_internal(s, pkt);
            if (ret < 0)
                return ret;
            goto return_packet;
        }
    
        for (;;) {
            PacketList *pktl = s->internal->packet_buffer;
            if (pktl) {
                AVPacket *next_pkt = &pktl->pkt;
                if (next_pkt->dts != AV_NOPTS_VALUE) {
                    int wrap_bits = s->streams[next_pkt->stream_index]->pts_wrap_bits;
                    int64_t last_dts = next_pkt->dts;
                    while (pktl && next_pkt->pts == AV_NOPTS_VALUE) {
                        if (pktl->pkt.stream_index == next_pkt->stream_index &&
                            av_compare_mod(next_pkt->dts, pktl->pkt.dts, 2ULL << (wrap_bits - 1)) < 0) {
                            if (av_compare_mod(pktl->pkt.pts, pktl->pkt.dts, 2ULL << (wrap_bits - 1))) {
                                // 没有B帧
                                next_pkt->pts = pktl->pkt.dts;
                            }
                            if (last_dts != AV_NOPTS_VALUE) {
                                last_dts = pktl->pkt.dts;
                            }
                        }
                        pktl = pktl->next;
                    }
                    if (eof && next_pkt->pts == AV_NOPTS_VALUE && last_dts != AV_NOPTS_VALUE) {
                        next_pkt->pts = last_dts + next_pkt->duration;
                    }
                    pktl = s->internal->packet_buffer;
                }
                // 从packet缓冲区读取packet
                st = s->streams[next_pkt->stream_index];
                if (!(next_pkt->pts == AV_NOPTS_VALUE && st->discard < AVDISCARD_ALL &&
                      next_pkt->dts != AV_NOPTS_VALUE && !eof)) {
                    ret = avpriv_packet_list_get(&s->internal->packet_buffer,
                                                   &s->internal->packet_buffer_end, pkt);
                    goto return_packet;
                }
            }
            // 调用内部方法读取一帧
            ret = read_frame_internal(s, pkt);
            if (ret < 0) {
                if (pktl && ret != AVERROR(EAGAIN)) {
                    eof = 1;
                    continue;
                } else
                    return ret;
            }
            ret = avpriv_packet_list_put(&s->internal->packet_buffer,
                                     &s->internal->packet_buffer_end,
                                     pkt, NULL, 0);
            if (ret < 0) {
                av_packet_unref(pkt);
                return ret;
            }
        }
    return_packet:
        ......
        return ret;
    }

    3、av_read_frame_internal

    av_read_frame_internal()为内部读取一帧数据,主要调用ff_read_packet()和parse_packet(),具体代码如下:

    static int read_frame_internal(AVFormatContext *s, AVPacket *pkt)
    {
        int ret, i, got_packet = 0;
        AVDictionary *metadata = NULL;
    
        while (!got_packet && !s->internal->parse_queue) {
            AVStream *st;
            // 读取下一个数据包
            ret = ff_read_packet(s, pkt);
            if (ret < 0) {
                if (ret == AVERROR(EAGAIN))
                    return ret;
                // 刷新解析器
                for (i = 0; i < s->nb_streams; i++) {
                    st = s->streams[i];
                    if (st->parser && st->need_parsing)
                        parse_packet(s, pkt, st->index, 1);
                }
                break;
            }
            ret = 0;
            st  = s->streams[pkt->stream_index];
            st->event_flags |= AVSTREAM_EVENT_FLAG_NEW_PACKETS;
            if (st->internal->need_context_update) {
                if (avcodec_is_open(st->internal->avctx)) {
                    avcodec_close(st->internal->avctx);
                    st->internal->info->found_decoder = 0;
                }
                // 关闭解析器,因为它依赖于codec
                if (st->parser && st->internal->avctx->codec_id != st->codecpar->codec_id) {
                    av_parser_close(st->parser);
                    st->parser = NULL;
                }
                ret = avcodec_parameters_to_context(st->internal->avctx, st->codecpar);
                if (ret < 0) {
                    av_packet_unref(pkt);
                    return ret;
                }
                st->internal->need_context_update = 0;
            }
            if (st->need_parsing && !st->parser && !(s->flags & AVFMT_FLAG_NOPARSE)) {
    			// 初始化解析器
                st->parser = av_parser_init(st->codecpar->codec_id);
                if (!st->parser) {
                    st->need_parsing = AVSTREAM_PARSE_NONE;
                } else if (st->need_parsing == AVSTREAM_PARSE_HEADERS)
                    st->parser->flags |= PARSER_FLAG_COMPLETE_FRAMES;
                else if (st->need_parsing == AVSTREAM_PARSE_FULL_ONCE)
                    st->parser->flags |= PARSER_FLAG_ONCE;
                else if (st->need_parsing == AVSTREAM_PARSE_FULL_RAW)
                    st->parser->flags |= PARSER_FLAG_USE_CODEC_TS;
            }
            if (!st->need_parsing || !st->parser) {
                // 不需要解析,直接输出packet
                compute_pkt_fields(s, st, NULL, pkt, AV_NOPTS_VALUE, AV_NOPTS_VALUE);
                if ((s->iformat->flags & AVFMT_GENERIC_INDEX) &&
                    (pkt->flags & AV_PKT_FLAG_KEY) && pkt->dts != AV_NOPTS_VALUE) {
                    ff_reduce_index(s, st->index);
                    av_add_index_entry(st, pkt->pos, pkt->dts,
                                       0, 0, AVINDEX_KEYFRAME);
                }
                got_packet = 1;
            } else if (st->discard < AVDISCARD_ALL) {
    			// 解析packet
                if ((ret = parse_packet(s, pkt, pkt->stream_index, 0)) < 0)
                    return ret;
                st->codecpar->sample_rate = st->internal->avctx->sample_rate;
                st->codecpar->bit_rate = st->internal->avctx->bit_rate;
                st->codecpar->channels = st->internal->avctx->channels;
                st->codecpar->channel_layout = st->internal->avctx->channel_layout;
                st->codecpar->codec_id = st->internal->avctx->codec_id;
            } else {
                av_packet_unref(pkt);
            }
            if (pkt->flags & AV_PKT_FLAG_KEY)
                st->internal->skip_to_keyframe = 0;
            if (st->internal->skip_to_keyframe) {
                av_packet_unref(pkt);
                got_packet = 0;
            }
        }
        ......
    
        return ret;
    }

    4、ff_read_packet

    ff_read_packet()主要是调用AVInputFormat指向的read_packet()方法来读取数据包:

    int ff_read_packet(AVFormatContext *s, AVPacket *pkt)
    {
        ......
        for (;;) {
            PacketList *pktl = s->internal->raw_packet_buffer;
            const AVPacket *pkt1;
            if (pktl) {
                st = s->streams[pktl->pkt.stream_index];
                if (s->internal->raw_packet_buffer_remaining_size <= 0)
                    if ((err = probe_codec(s, st, NULL)) < 0)
                        return err;
                if (st->internal->request_probe <= 0) {
                    avpriv_packet_list_get(&s->internal->raw_packet_buffer,
                                       &s->internal->raw_packet_buffer_end, pkt);
                    s->internal->raw_packet_buffer_remaining_size += pkt->size;
                    return 0;
                }
            }
            // 读取数据包
            ret = s->iformat->read_packet(s, pkt);
            if (ret < 0) {
                av_packet_unref(pkt);
                if (ret == FFERROR_REDO)
                    continue;
                if (!pktl || ret == AVERROR(EAGAIN))
                    return ret;
                for (i = 0; i < s->nb_streams; i++) {
                    st = s->streams[i];
                    if (st->probe_packets || st->internal->request_probe > 0)
                        if ((err = probe_codec(s, st, NULL)) < 0)
                            return err;
                }
                continue;
            }
            err = av_packet_make_refcounted(pkt);
            if (err < 0) {
                av_packet_unref(pkt);
                return err;
            }
            if (pkt->flags & AV_PKT_FLAG_CORRUPT) {
                if (s->flags & AVFMT_FLAG_DISCARD_CORRUPT) {
                    av_log(s, AV_LOG_WARNING, ", dropping it.\n");
                    av_packet_unref(pkt);
                    continue;
                }
            }
            st = s->streams[pkt->stream_index];
            if (update_wrap_reference(s, st, pkt->stream_index, pkt) 
    			&& st->internal->pts_wrap_behavior == AV_PTS_WRAP_SUB_OFFSET) {
                // 校正第一个时间戳
                if (!is_relative(st->first_dts))
                    st->first_dts = wrap_timestamp(st, st->first_dts);
                if (!is_relative(st->start_time))
                    st->start_time = wrap_timestamp(st, st->start_time);
                if (!is_relative(st->cur_dts))
                    st->cur_dts = wrap_timestamp(st, st->cur_dts);
            }
            pkt->dts = wrap_timestamp(st, pkt->dts);
            pkt->pts = wrap_timestamp(st, pkt->pts);
            force_codec_ids(s, st);
            /* TODO: audio: time filter; video: frame reordering (pts != dts) */
            if (s->use_wallclock_as_timestamps)
                pkt->dts = pkt->pts = av_rescale_q(av_gettime(), AV_TIME_BASE_Q, st->time_base);
            if (!pktl && st->internal->request_probe <= 0)
                return ret;
            err = avpriv_packet_list_put(&s->internal->raw_packet_buffer,
                                     &s->internal->raw_packet_buffer_end,
                                     pkt, NULL, 0);
            if (err < 0) {
                av_packet_unref(pkt);
                return err;
            }
            pkt1 = &s->internal->raw_packet_buffer_end->pkt;
            s->internal->raw_packet_buffer_remaining_size -= pkt1->size;
            if ((err = probe_codec(s, st, pkt1)) < 0)
                return err;
        }
    }

    其中,read_packet()为函数指针。以mp4的解封装过程为例,位于libavformat/mov.c,对应的AVInputFormat如下:

    AVInputFormat ff_mov_demuxer = {
        .name           = "mov,mp4,m4a,3gp,3g2,mj2",
        .long_name      = NULL_IF_CONFIG_SMALL("QuickTime / MOV"),
        .priv_class     = &mov_class,
        .priv_data_size = sizeof(MOVContext),
        .extensions     = "mov,mp4,m4a,3gp,3g2,mj2,psp,m4b,ism,ismv,isma,f4v",
        .read_probe     = mov_probe,
        .read_header    = mov_read_header,
        .read_packet    = mov_read_packet,
        .read_close     = mov_read_close,
        .read_seek      = mov_read_seek,
        .flags          = AVFMT_NO_BYTE_SEEK | AVFMT_SEEK_TO_PTS,
    };

    那么iformat->read_packet()所指向的函数为mov_read_packet(),具体代码如下:

    static int mov_read_packet(AVFormatContext *s, AVPacket *pkt)
    {
        MOVContext *mov = s->priv_data;
        MOVStreamContext *sc;
        AVIndexEntry *sample;
        AVStream *st = NULL;
        int64_t current_index;
        int ret;
        mov->fc = s;
     retry:
        // 查找下一个sample
        sample = mov_find_next_sample(s, &st);
        ......
        if (st->discard != AVDISCARD_ALL) {
            // 读取数据包
            if (st->codecpar->codec_id == AV_CODEC_ID_EIA_608 && sample->size > 8)
                ret = get_eia608_packet(sc->pb, pkt, sample->size);
            else
                ret = av_get_packet(sc->pb, pkt, sample->size);
            if (ret < 0) {
                if (should_retry(sc->pb, ret)) {
                    mov_current_sample_dec(sc);
                }
                return ret;
            }
        }
        ......
        if (sc->ctts_data && sc->ctts_index < sc->ctts_count) {
            pkt->pts = pkt->dts + sc->dts_shift + sc->ctts_data[sc->ctts_index].duration;
            // 更新ctts上下文
            sc->ctts_sample++;
            if (sc->ctts_index < sc->ctts_count &&
                sc->ctts_data[sc->ctts_index].count == sc->ctts_sample) {
                sc->ctts_index++;
                sc->ctts_sample = 0;
            }
        } else {
            int64_t next_dts = (sc->current_sample < st->nb_index_entries) ?
                st->index_entries[sc->current_sample].timestamp : st->duration;
            if (next_dts >= pkt->dts)
                pkt->duration = next_dts - pkt->dts;
            pkt->pts = pkt->dts;
        }
        ......
        return 0;
    }

    5、parse_packet

    parse_packet()主要调用av_parser_parse2()来实现解析,代码如下:

    static int parse_packet(AVFormatContext *s, AVPacket *pkt,
                            int stream_index, int flush)
    {
        ......
        while (size > 0 || (flush && got_output)) {
            int len;
            int64_t next_pts = pkt->pts;
            int64_t next_dts = pkt->dts;
            // 真正去解析数据包
            len = av_parser_parse2(st->parser, st->internal->avctx,
                                   &out_pkt->data, &out_pkt->size, data, size,
                                   pkt->pts, pkt->dts, pkt->pos);
            ......
            // 设置时长
            out_pkt->duration = (st->parser->flags & PARSER_FLAG_COMPLETE_FRAMES) ? pkt->duration : 0;
            if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
                if (st->internal->avctx->sample_rate > 0) {
                    out_pkt->duration =
                        av_rescale_q_rnd(st->parser->duration,
                                         (AVRational) { 1, st->internal->avctx->sample_rate },
                                         st->time_base,
                                         AV_ROUND_DOWN);
                }
            }
            ......
    		// flag设为关键帧
            if (st->parser->key_frame == 1 ||
                (st->parser->key_frame == -1 &&
                 st->parser->pict_type == AV_PICTURE_TYPE_I))
                out_pkt->flags |= AV_PKT_FLAG_KEY;
            if (st->parser->key_frame == -1 && st->parser->pict_type ==AV_PICTURE_TYPE_NONE && (pkt->flags&AV_PKT_FLAG_KEY))
                out_pkt->flags |= AV_PKT_FLAG_KEY;
            ......
        }
        if (flush) {
            av_parser_close(st->parser);
            st->parser = NULL;
        }
    fail:
        av_packet_unref(pkt);
        return ret;
    }

    最终是调用libavcodec/parser.c的av_parser_parse2()方法去解析数据包。至于数据包解析,在下一篇文章与大家探讨分析。

    展开全文
  • python pandas.read_csv()函数详解

    万次阅读 多人点赞 2021-03-24 15:20:19
    这里将更新最新的最全面的read_csv()函数功能以及参数介绍,参考资料来源于官网。 目录pandas库简介csv文件格式简介函数介绍函数原型函数参数以及含义输入返回函数使用实例 pandas库简介 官方网站里详细说明了pandas...
  • linux脚本read的用法

    千次阅读 2020-08-14 22:21:53
    1.Read的一些选项  Read可以带有-a, -d, -e, -n, -p, -r, -t, 和 -s八个选项。 -a :将内容读入到数值中 echo -n "Input muliple values into an array:" read -a array echo "get ${#array[@]} values in array" ...
  • Read the Docs 文档管理

    万次阅读 2021-09-17 19:40:29
    Sphinx + GitHub + Read the Docs 的文档管理方法
  • Pandas read_excel()参数详解

    万次阅读 多人点赞 2020-05-28 16:22:48
    Pandas read_excel()参数使用详解 read_excel函数原型 def read_excel(io, sheet_name=0, header=0, names=None, index_col=None, parse_cols=None, usecols=None, squeez
  • java.io.EOFException: Can not read response from server.
  • Created by Jerry Wang on Jul 04,...READ TABLE WITH KEY 传入的是free search key, 支持仅仅传入primary key collection的某一个primary key或者secondary key。 可以使用RTTI的方式得到某个table的key 信息。
  • ReadView深入理解MySql MVCC原理

    千次阅读 热门讨论 2020-12-04 09:47:09
    在说MVCC机制前我们先了解ReadView。 ReadView是什么呢?在我们平时执行一个事务的时候,就会生成一个ReadView,ReadView的组成结构大致如下 参数说明: creator_trx_id:当前事务id m_ids:所有事务的事务id min_trx...
  • IDEA: vue文件 File is read-only

    千次阅读 2022-03-08 07:38:17
    今天有个同学问我是vue文件设置了什么权限吗?文件只读操作。 解决方法;这是因为文件主动或者被动被锁定了,选择相应文件,点击File---Make File Writable处理解决即可。
  • pd.read_csv用法

    万次阅读 多人点赞 2019-04-17 22:16:39
    pd.read_csv(filepath_or_buffer, sep=’, ‘, delimiter=None, header=’infer’, names=None, index_col=None, usecols=None, squeeze=False, prefix=None, mangle_dupe_cols=True, dtype=None, engine=None, ...
  • Linux下出现Read-only file system解决办法

    千次阅读 2021-11-04 14:41:18
    涉及到修改/保存条目等需要写磁盘操作的命令都无法使用(如tar、cp、mv、rm、chmod、chown、wget下载等指令),总是提示Read-only file system,也就是说系统是只读的,什么也写不了。 解决方案 查看/etc/fstab文件...
  • Socket笔记之Read timed out深入分析

    万次阅读 2018-09-10 10:44:44
    ReadTimedOut深入分析 PlainSocketImpl.c Java_java_net_PlainSocketImpl_socketSetOption read()时 Java_java_net_SocketInputStream_socketRead0 solaris/native/java/net/bsd_close.c 总结 Read...
  • 记录最近开发遇到一个这样的错误,Can not read response from server. Expected to read 4 bytes, read 0 bytes be,执行出错的第三是在定时任务,3秒一次执行,查询数据库的时候抛的错误 经过网上一堆查询...
  • read()详解

    千次阅读 2021-06-19 15:25:31
    read() 此方法一个字节一个字节的读取,从输入流中读取数据的下一个字节,**返回 0 到 255 范围内的 int 字节值,**如果因为已经到达流末尾而没有可用的字节,则返回值 -1。 read (byte[] b) 此方法按b进行读取,...
  • read函数的返回值问题

    千次阅读 2019-09-15 15:32:14
    Read函数读取字符串返回值的问题 1. 前言 在学习socket编程的途中, 通过客户端给服务端发送字符串,然后服务端通过read或者recv来读取数据,然后返回读取的字节数. 我在想read返回的读取字节数有没有包含'\0'或者'\n'...
  • uninitialized urandom read

    千次阅读 2019-09-20 18:53:30
    [ 0.637733] random: hwclock: uninitialized urandom read (8 bytes read) [ 0.821425] random: sh: uninitialized urandom read (8 bytes read) [ 11.923501] random: fast init done [ 13.111697] random: ...
  • 推荐使用notepad FileInputStream中read()及read(byte b[])的用法 1、首先看read()方法 /** * Reads a byte of data from this input stream. This method blocks * if no input is yet available. * * @return the ...
  • 1:read_sql_query() 读取自定义数据(通过SQL语句) import pandas as pd pd.read_sql_query(sql, con, index_col=None, coerce_float=True, params=None, parse_dates=None,chunksize=None) read_sql_query...
  • 并发和Read-copy update(RCU)

    万次阅读 2020-06-04 06:20:48
    在上一篇文章中的并发和ABA问题的介绍中,我们提到了要解决ABA中的memory reclamation...RCU(Read-copy update)是一种同步机制,并在2002年被加入了Linux内核中。它的优点就是可以在更新的过程中,运行多个reader进行读
  • 【Python】pd.read_excel应用

    万次阅读 2019-08-12 23:21:27
    第一次运行必须带上定义:import pandas...pd.read_excel(1) read_excel(io, sheet_name, header, names, index_col, parse_cols, usecols, squeeze, dtype, engine, converters, true_values, false_values, ski...
  • MacOS (Catalina):显示Read-only file system的对应方法

    万次阅读 多人点赞 2020-02-15 16:22:30
    在Catalina版的macOS上以root身份登录,发现创建类似/data之类的目录会会提示Read-only file system,这篇文章介绍一下原因和对应方法。
  • linux文件系统四 VFS数据读取vfs_read

    千次阅读 2019-03-29 09:54:51
    一、vfs_read的调用流程: 二、VFS层调用流程 1、系统调用sys_read会调用到vfs层的__vfs_read接口如下,在vfs层接口会调用大具体的文件系统的 操作接口: //kernel-4.9/fs/read_write.c ssize_t __vfs_read...
  • fatfs文件系统详解之f_read函数分析

    千次阅读 2020-05-31 17:39:01
    f_read函数分析 下面是f_read()函数的源码: FRESULT f_read ( FIL* fp, /* Pointer to the file object */ void* buff, /* Pointer to data buffer */ UINT btr, /* Number of bytes to read */ UINT* br /* ...
  • springboot项目启动时连接mysql时提示,Can not read response from server. Expected to read 4 bytes, read 0 bytes be…… 解决办法: 1、检查数据库连接池的参数(尽量开发环境连接数不要设置太大) spring....
  • p.p1 {margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px 'Helvetica Neue'; color: #454545} span.s1 {font: 12.0px '.PingFang SC'}Can not read response from server. Expected to read 4 bytes, read 0 bytes bef
  • 在做android开发过程中,我们经常会用到logcat,通过logcat可以更直接的看出程序执行的顺序以及开发产生的日志信息,但是,我们在开发过程中也经常看到logcat输出read: Unexpected EOF!异常,然后日志就不在打印了。...
  • 总结了Fortran中WRITE和READ语句的格式化使用方法。

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 3,458,754
精华内容 1,383,501
关键字:

read

友情链接: ID卡软件.rar