├── .gitignore ├── COPYING.GPL ├── COPYING.LGPL ├── README ├── build.sh ├── ffmpeg_fas.c ├── ffmpeg_fas.def ├── ffmpeg_fas.h ├── ffmpeg_fas.vcproj ├── private_errors.h ├── seek_indices.c ├── seek_indices.h └── test ├── build.sh ├── dump_frames.c ├── dump_keyframes.c ├── external_seek_test.c ├── generate_seek_table.c ├── movie_info.c ├── run_test.py ├── seek_test.c ├── show_seek_table.c └── test_support.h /.gitignore: -------------------------------------------------------------------------------- 1 | \#* 2 | *~ 3 | .svn -------------------------------------------------------------------------------- /COPYING.GPL: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | , 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | -------------------------------------------------------------------------------- /COPYING.LGPL: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 2.1, February 1999 3 | 4 | Copyright (C) 1991, 1999 Free Software Foundation, Inc. 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | [This is the first released version of the Lesser GPL. It also counts 10 | as the successor of the GNU Library Public License, version 2, hence 11 | the version number 2.1.] 12 | 13 | Preamble 14 | 15 | The licenses for most software are designed to take away your 16 | freedom to share and change it. By contrast, the GNU General Public 17 | Licenses are intended to guarantee your freedom to share and change 18 | free software--to make sure the software is free for all its users. 19 | 20 | This license, the Lesser General Public License, applies to some 21 | specially designated software packages--typically libraries--of the 22 | Free Software Foundation and other authors who decide to use it. You 23 | can use it too, but we suggest you first think carefully about whether 24 | this license or the ordinary General Public License is the better 25 | strategy to use in any particular case, based on the explanations below. 26 | 27 | When we speak of free software, we are referring to freedom of use, 28 | not price. Our General Public Licenses are designed to make sure that 29 | you have the freedom to distribute copies of free software (and charge 30 | for this service if you wish); that you receive source code or can get 31 | it if you want it; that you can change the software and use pieces of 32 | it in new free programs; and that you are informed that you can do 33 | these things. 34 | 35 | To protect your rights, we need to make restrictions that forbid 36 | distributors to deny you these rights or to ask you to surrender these 37 | rights. These restrictions translate to certain responsibilities for 38 | you if you distribute copies of the library or if you modify it. 39 | 40 | For example, if you distribute copies of the library, whether gratis 41 | or for a fee, you must give the recipients all the rights that we gave 42 | you. You must make sure that they, too, receive or can get the source 43 | code. If you link other code with the library, you must provide 44 | complete object files to the recipients, so that they can relink them 45 | with the library after making changes to the library and recompiling 46 | it. And you must show them these terms so they know their rights. 47 | 48 | We protect your rights with a two-step method: (1) we copyright the 49 | library, and (2) we offer you this license, which gives you legal 50 | permission to copy, distribute and/or modify the library. 51 | 52 | To protect each distributor, we want to make it very clear that 53 | there is no warranty for the free library. Also, if the library is 54 | modified by someone else and passed on, the recipients should know 55 | that what they have is not the original version, so that the original 56 | author's reputation will not be affected by problems that might be 57 | introduced by others. 58 | 59 | Finally, software patents pose a constant threat to the existence of 60 | any free program. We wish to make sure that a company cannot 61 | effectively restrict the users of a free program by obtaining a 62 | restrictive license from a patent holder. Therefore, we insist that 63 | any patent license obtained for a version of the library must be 64 | consistent with the full freedom of use specified in this license. 65 | 66 | Most GNU software, including some libraries, is covered by the 67 | ordinary GNU General Public License. This license, the GNU Lesser 68 | General Public License, applies to certain designated libraries, and 69 | is quite different from the ordinary General Public License. We use 70 | this license for certain libraries in order to permit linking those 71 | libraries into non-free programs. 72 | 73 | When a program is linked with a library, whether statically or using 74 | a shared library, the combination of the two is legally speaking a 75 | combined work, a derivative of the original library. The ordinary 76 | General Public License therefore permits such linking only if the 77 | entire combination fits its criteria of freedom. The Lesser General 78 | Public License permits more lax criteria for linking other code with 79 | the library. 80 | 81 | We call this license the "Lesser" General Public License because it 82 | does Less to protect the user's freedom than the ordinary General 83 | Public License. It also provides other free software developers Less 84 | of an advantage over competing non-free programs. These disadvantages 85 | are the reason we use the ordinary General Public License for many 86 | libraries. However, the Lesser license provides advantages in certain 87 | special circumstances. 88 | 89 | For example, on rare occasions, there may be a special need to 90 | encourage the widest possible use of a certain library, so that it becomes 91 | a de-facto standard. To achieve this, non-free programs must be 92 | allowed to use the library. A more frequent case is that a free 93 | library does the same job as widely used non-free libraries. In this 94 | case, there is little to gain by limiting the free library to free 95 | software only, so we use the Lesser General Public License. 96 | 97 | In other cases, permission to use a particular library in non-free 98 | programs enables a greater number of people to use a large body of 99 | free software. For example, permission to use the GNU C Library in 100 | non-free programs enables many more people to use the whole GNU 101 | operating system, as well as its variant, the GNU/Linux operating 102 | system. 103 | 104 | Although the Lesser General Public License is Less protective of the 105 | users' freedom, it does ensure that the user of a program that is 106 | linked with the Library has the freedom and the wherewithal to run 107 | that program using a modified version of the Library. 108 | 109 | The precise terms and conditions for copying, distribution and 110 | modification follow. Pay close attention to the difference between a 111 | "work based on the library" and a "work that uses the library". The 112 | former contains code derived from the library, whereas the latter must 113 | be combined with the library in order to run. 114 | 115 | GNU LESSER GENERAL PUBLIC LICENSE 116 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 117 | 118 | 0. This License Agreement applies to any software library or other 119 | program which contains a notice placed by the copyright holder or 120 | other authorized party saying it may be distributed under the terms of 121 | this Lesser General Public License (also called "this License"). 122 | Each licensee is addressed as "you". 123 | 124 | A "library" means a collection of software functions and/or data 125 | prepared so as to be conveniently linked with application programs 126 | (which use some of those functions and data) to form executables. 127 | 128 | The "Library", below, refers to any such software library or work 129 | which has been distributed under these terms. A "work based on the 130 | Library" means either the Library or any derivative work under 131 | copyright law: that is to say, a work containing the Library or a 132 | portion of it, either verbatim or with modifications and/or translated 133 | straightforwardly into another language. (Hereinafter, translation is 134 | included without limitation in the term "modification".) 135 | 136 | "Source code" for a work means the preferred form of the work for 137 | making modifications to it. For a library, complete source code means 138 | all the source code for all modules it contains, plus any associated 139 | interface definition files, plus the scripts used to control compilation 140 | and installation of the library. 141 | 142 | Activities other than copying, distribution and modification are not 143 | covered by this License; they are outside its scope. The act of 144 | running a program using the Library is not restricted, and output from 145 | such a program is covered only if its contents constitute a work based 146 | on the Library (independent of the use of the Library in a tool for 147 | writing it). Whether that is true depends on what the Library does 148 | and what the program that uses the Library does. 149 | 150 | 1. You may copy and distribute verbatim copies of the Library's 151 | complete source code as you receive it, in any medium, provided that 152 | you conspicuously and appropriately publish on each copy an 153 | appropriate copyright notice and disclaimer of warranty; keep intact 154 | all the notices that refer to this License and to the absence of any 155 | warranty; and distribute a copy of this License along with the 156 | Library. 157 | 158 | You may charge a fee for the physical act of transferring a copy, 159 | and you may at your option offer warranty protection in exchange for a 160 | fee. 161 | 162 | 2. You may modify your copy or copies of the Library or any portion 163 | of it, thus forming a work based on the Library, and copy and 164 | distribute such modifications or work under the terms of Section 1 165 | above, provided that you also meet all of these conditions: 166 | 167 | a) The modified work must itself be a software library. 168 | 169 | b) You must cause the files modified to carry prominent notices 170 | stating that you changed the files and the date of any change. 171 | 172 | c) You must cause the whole of the work to be licensed at no 173 | charge to all third parties under the terms of this License. 174 | 175 | d) If a facility in the modified Library refers to a function or a 176 | table of data to be supplied by an application program that uses 177 | the facility, other than as an argument passed when the facility 178 | is invoked, then you must make a good faith effort to ensure that, 179 | in the event an application does not supply such function or 180 | table, the facility still operates, and performs whatever part of 181 | its purpose remains meaningful. 182 | 183 | (For example, a function in a library to compute square roots has 184 | a purpose that is entirely well-defined independent of the 185 | application. Therefore, Subsection 2d requires that any 186 | application-supplied function or table used by this function must 187 | be optional: if the application does not supply it, the square 188 | root function must still compute square roots.) 189 | 190 | These requirements apply to the modified work as a whole. If 191 | identifiable sections of that work are not derived from the Library, 192 | and can be reasonably considered independent and separate works in 193 | themselves, then this License, and its terms, do not apply to those 194 | sections when you distribute them as separate works. But when you 195 | distribute the same sections as part of a whole which is a work based 196 | on the Library, the distribution of the whole must be on the terms of 197 | this License, whose permissions for other licensees extend to the 198 | entire whole, and thus to each and every part regardless of who wrote 199 | it. 200 | 201 | Thus, it is not the intent of this section to claim rights or contest 202 | your rights to work written entirely by you; rather, the intent is to 203 | exercise the right to control the distribution of derivative or 204 | collective works based on the Library. 205 | 206 | In addition, mere aggregation of another work not based on the Library 207 | with the Library (or with a work based on the Library) on a volume of 208 | a storage or distribution medium does not bring the other work under 209 | the scope of this License. 210 | 211 | 3. You may opt to apply the terms of the ordinary GNU General Public 212 | License instead of this License to a given copy of the Library. To do 213 | this, you must alter all the notices that refer to this License, so 214 | that they refer to the ordinary GNU General Public License, version 2, 215 | instead of to this License. (If a newer version than version 2 of the 216 | ordinary GNU General Public License has appeared, then you can specify 217 | that version instead if you wish.) Do not make any other change in 218 | these notices. 219 | 220 | Once this change is made in a given copy, it is irreversible for 221 | that copy, so the ordinary GNU General Public License applies to all 222 | subsequent copies and derivative works made from that copy. 223 | 224 | This option is useful when you wish to copy part of the code of 225 | the Library into a program that is not a library. 226 | 227 | 4. You may copy and distribute the Library (or a portion or 228 | derivative of it, under Section 2) in object code or executable form 229 | under the terms of Sections 1 and 2 above provided that you accompany 230 | it with the complete corresponding machine-readable source code, which 231 | must be distributed under the terms of Sections 1 and 2 above on a 232 | medium customarily used for software interchange. 233 | 234 | If distribution of object code is made by offering access to copy 235 | from a designated place, then offering equivalent access to copy the 236 | source code from the same place satisfies the requirement to 237 | distribute the source code, even though third parties are not 238 | compelled to copy the source along with the object code. 239 | 240 | 5. A program that contains no derivative of any portion of the 241 | Library, but is designed to work with the Library by being compiled or 242 | linked with it, is called a "work that uses the Library". Such a 243 | work, in isolation, is not a derivative work of the Library, and 244 | therefore falls outside the scope of this License. 245 | 246 | However, linking a "work that uses the Library" with the Library 247 | creates an executable that is a derivative of the Library (because it 248 | contains portions of the Library), rather than a "work that uses the 249 | library". The executable is therefore covered by this License. 250 | Section 6 states terms for distribution of such executables. 251 | 252 | When a "work that uses the Library" uses material from a header file 253 | that is part of the Library, the object code for the work may be a 254 | derivative work of the Library even though the source code is not. 255 | Whether this is true is especially significant if the work can be 256 | linked without the Library, or if the work is itself a library. The 257 | threshold for this to be true is not precisely defined by law. 258 | 259 | If such an object file uses only numerical parameters, data 260 | structure layouts and accessors, and small macros and small inline 261 | functions (ten lines or less in length), then the use of the object 262 | file is unrestricted, regardless of whether it is legally a derivative 263 | work. (Executables containing this object code plus portions of the 264 | Library will still fall under Section 6.) 265 | 266 | Otherwise, if the work is a derivative of the Library, you may 267 | distribute the object code for the work under the terms of Section 6. 268 | Any executables containing that work also fall under Section 6, 269 | whether or not they are linked directly with the Library itself. 270 | 271 | 6. As an exception to the Sections above, you may also combine or 272 | link a "work that uses the Library" with the Library to produce a 273 | work containing portions of the Library, and distribute that work 274 | under terms of your choice, provided that the terms permit 275 | modification of the work for the customer's own use and reverse 276 | engineering for debugging such modifications. 277 | 278 | You must give prominent notice with each copy of the work that the 279 | Library is used in it and that the Library and its use are covered by 280 | this License. You must supply a copy of this License. If the work 281 | during execution displays copyright notices, you must include the 282 | copyright notice for the Library among them, as well as a reference 283 | directing the user to the copy of this License. Also, you must do one 284 | of these things: 285 | 286 | a) Accompany the work with the complete corresponding 287 | machine-readable source code for the Library including whatever 288 | changes were used in the work (which must be distributed under 289 | Sections 1 and 2 above); and, if the work is an executable linked 290 | with the Library, with the complete machine-readable "work that 291 | uses the Library", as object code and/or source code, so that the 292 | user can modify the Library and then relink to produce a modified 293 | executable containing the modified Library. (It is understood 294 | that the user who changes the contents of definitions files in the 295 | Library will not necessarily be able to recompile the application 296 | to use the modified definitions.) 297 | 298 | b) Use a suitable shared library mechanism for linking with the 299 | Library. A suitable mechanism is one that (1) uses at run time a 300 | copy of the library already present on the user's computer system, 301 | rather than copying library functions into the executable, and (2) 302 | will operate properly with a modified version of the library, if 303 | the user installs one, as long as the modified version is 304 | interface-compatible with the version that the work was made with. 305 | 306 | c) Accompany the work with a written offer, valid for at 307 | least three years, to give the same user the materials 308 | specified in Subsection 6a, above, for a charge no more 309 | than the cost of performing this distribution. 310 | 311 | d) If distribution of the work is made by offering access to copy 312 | from a designated place, offer equivalent access to copy the above 313 | specified materials from the same place. 314 | 315 | e) Verify that the user has already received a copy of these 316 | materials or that you have already sent this user a copy. 317 | 318 | For an executable, the required form of the "work that uses the 319 | Library" must include any data and utility programs needed for 320 | reproducing the executable from it. However, as a special exception, 321 | the materials to be distributed need not include anything that is 322 | normally distributed (in either source or binary form) with the major 323 | components (compiler, kernel, and so on) of the operating system on 324 | which the executable runs, unless that component itself accompanies 325 | the executable. 326 | 327 | It may happen that this requirement contradicts the license 328 | restrictions of other proprietary libraries that do not normally 329 | accompany the operating system. Such a contradiction means you cannot 330 | use both them and the Library together in an executable that you 331 | distribute. 332 | 333 | 7. You may place library facilities that are a work based on the 334 | Library side-by-side in a single library together with other library 335 | facilities not covered by this License, and distribute such a combined 336 | library, provided that the separate distribution of the work based on 337 | the Library and of the other library facilities is otherwise 338 | permitted, and provided that you do these two things: 339 | 340 | a) Accompany the combined library with a copy of the same work 341 | based on the Library, uncombined with any other library 342 | facilities. This must be distributed under the terms of the 343 | Sections above. 344 | 345 | b) Give prominent notice with the combined library of the fact 346 | that part of it is a work based on the Library, and explaining 347 | where to find the accompanying uncombined form of the same work. 348 | 349 | 8. You may not copy, modify, sublicense, link with, or distribute 350 | the Library except as expressly provided under this License. Any 351 | attempt otherwise to copy, modify, sublicense, link with, or 352 | distribute the Library is void, and will automatically terminate your 353 | rights under this License. However, parties who have received copies, 354 | or rights, from you under this License will not have their licenses 355 | terminated so long as such parties remain in full compliance. 356 | 357 | 9. You are not required to accept this License, since you have not 358 | signed it. However, nothing else grants you permission to modify or 359 | distribute the Library or its derivative works. These actions are 360 | prohibited by law if you do not accept this License. Therefore, by 361 | modifying or distributing the Library (or any work based on the 362 | Library), you indicate your acceptance of this License to do so, and 363 | all its terms and conditions for copying, distributing or modifying 364 | the Library or works based on it. 365 | 366 | 10. Each time you redistribute the Library (or any work based on the 367 | Library), the recipient automatically receives a license from the 368 | original licensor to copy, distribute, link with or modify the Library 369 | subject to these terms and conditions. You may not impose any further 370 | restrictions on the recipients' exercise of the rights granted herein. 371 | You are not responsible for enforcing compliance by third parties with 372 | this License. 373 | 374 | 11. If, as a consequence of a court judgment or allegation of patent 375 | infringement or for any other reason (not limited to patent issues), 376 | conditions are imposed on you (whether by court order, agreement or 377 | otherwise) that contradict the conditions of this License, they do not 378 | excuse you from the conditions of this License. If you cannot 379 | distribute so as to satisfy simultaneously your obligations under this 380 | License and any other pertinent obligations, then as a consequence you 381 | may not distribute the Library at all. For example, if a patent 382 | license would not permit royalty-free redistribution of the Library by 383 | all those who receive copies directly or indirectly through you, then 384 | the only way you could satisfy both it and this License would be to 385 | refrain entirely from distribution of the Library. 386 | 387 | If any portion of this section is held invalid or unenforceable under any 388 | particular circumstance, the balance of the section is intended to apply, 389 | and the section as a whole is intended to apply in other circumstances. 390 | 391 | It is not the purpose of this section to induce you to infringe any 392 | patents or other property right claims or to contest validity of any 393 | such claims; this section has the sole purpose of protecting the 394 | integrity of the free software distribution system which is 395 | implemented by public license practices. Many people have made 396 | generous contributions to the wide range of software distributed 397 | through that system in reliance on consistent application of that 398 | system; it is up to the author/donor to decide if he or she is willing 399 | to distribute software through any other system and a licensee cannot 400 | impose that choice. 401 | 402 | This section is intended to make thoroughly clear what is believed to 403 | be a consequence of the rest of this License. 404 | 405 | 12. If the distribution and/or use of the Library is restricted in 406 | certain countries either by patents or by copyrighted interfaces, the 407 | original copyright holder who places the Library under this License may add 408 | an explicit geographical distribution limitation excluding those countries, 409 | so that distribution is permitted only in or among countries not thus 410 | excluded. In such case, this License incorporates the limitation as if 411 | written in the body of this License. 412 | 413 | 13. The Free Software Foundation may publish revised and/or new 414 | versions of the Lesser General Public License from time to time. 415 | Such new versions will be similar in spirit to the present version, 416 | but may differ in detail to address new problems or concerns. 417 | 418 | Each version is given a distinguishing version number. If the Library 419 | specifies a version number of this License which applies to it and 420 | "any later version", you have the option of following the terms and 421 | conditions either of that version or of any later version published by 422 | the Free Software Foundation. If the Library does not specify a 423 | license version number, you may choose any version ever published by 424 | the Free Software Foundation. 425 | 426 | 14. If you wish to incorporate parts of the Library into other free 427 | programs whose distribution conditions are incompatible with these, 428 | write to the author to ask for permission. For software which is 429 | copyrighted by the Free Software Foundation, write to the Free 430 | Software Foundation; we sometimes make exceptions for this. Our 431 | decision will be guided by the two goals of preserving the free status 432 | of all derivatives of our free software and of promoting the sharing 433 | and reuse of software generally. 434 | 435 | NO WARRANTY 436 | 437 | 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO 438 | WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. 439 | EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR 440 | OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY 441 | KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE 442 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 443 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE 444 | LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME 445 | THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 446 | 447 | 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN 448 | WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY 449 | AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU 450 | FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR 451 | CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE 452 | LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING 453 | RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A 454 | FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF 455 | SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 456 | DAMAGES. 457 | 458 | END OF TERMS AND CONDITIONS 459 | 460 | How to Apply These Terms to Your New Libraries 461 | 462 | If you develop a new library, and you want it to be of the greatest 463 | possible use to the public, we recommend making it free software that 464 | everyone can redistribute and change. You can do so by permitting 465 | redistribution under these terms (or, alternatively, under the terms of the 466 | ordinary General Public License). 467 | 468 | To apply these terms, attach the following notices to the library. It is 469 | safest to attach them to the start of each source file to most effectively 470 | convey the exclusion of warranty; and each file should have at least the 471 | "copyright" line and a pointer to where the full notice is found. 472 | 473 | 474 | Copyright (C) 475 | 476 | This library is free software; you can redistribute it and/or 477 | modify it under the terms of the GNU Lesser General Public 478 | License as published by the Free Software Foundation; either 479 | version 2.1 of the License, or (at your option) any later version. 480 | 481 | This library is distributed in the hope that it will be useful, 482 | but WITHOUT ANY WARRANTY; without even the implied warranty of 483 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 484 | Lesser General Public License for more details. 485 | 486 | You should have received a copy of the GNU Lesser General Public 487 | License along with this library; if not, write to the Free Software 488 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 489 | 490 | Also add information on how to contact you by electronic and paper mail. 491 | 492 | You should also get your employer (if you work as a programmer) or your 493 | school, if any, to sign a "copyright disclaimer" for the library, if 494 | necessary. Here is a sample; alter the names: 495 | 496 | Yoyodyne, Inc., hereby disclaims all copyright interest in the 497 | library `Frob' (a library for tweaking knobs) written by James Random Hacker. 498 | 499 | , 1 April 1990 500 | Ty Coon, President of Vice 501 | 502 | That's all there is to it! 503 | 504 | 505 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | Released under Lesser GNU Public License (LGPL) 2 | 3 | This is an extension to the ffmpeg video decoding library meant to support 4 | a variety of extra functionality in support of video processing applications. 5 | The primary additional feature added is the ability to do frame-accurate seeking 6 | (by frame number). This is accomplished in a codec/format independant manner 7 | using seek tables. 8 | 9 | It has been built and tested under Linux and Windows. 10 | 11 | **NOTE [12/09]**: 12 | This package hasn't been kept fully up-to-date with 13 | ffmpeg's changing API. Some modification is necessary to remove calls to deprecated 14 | ffmpeg functionality. Patches welcome. 15 | ***************** 16 | 17 | Features: 18 | 1) Simplified interface for video processing 19 | 2) Frame-accurate seeking using a seek-table 20 | 3) Online creation of a seek-table through normal decoding 21 | 4) Saving and loading of seek-tables 22 | 23 | Getting up and running: 24 | The frame-accurate seek library extension to ffmpeg requires ffmpeg. 25 | Getting the most recent version of ffmpeg and building it from source is 26 | recommended: 27 | 28 | svn checkout svn://svn.mplayerhq.hu/ffmpeg/trunk ffmpeg 29 | 30 | The test/example build script requires ffmpeg be checked out (or symlinked) 31 | and built (./configure ; make) from the base directory. -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | cd `dirname $0` 2 | FFMPEG_BASEDIR=./ffmpeg/ 3 | 4 | rm -rf lib 5 | mkdir lib 6 | 7 | gcc ffmpeg_fas.c seek_indices.c -Iffmpeg ffmpeg/libavformat/libavformat.a ffmpeg/libavcodec/libavcodec.a ffmpeg/libavutil/libavutil.a -O2 -shared -o lib/libffmpeg_fas.so 8 | gcc -c ffmpeg_fas.c seek_indices.c -O2 -I$FFMPEG_BASEDIR 9 | ar rc lib/libffmpeg_fas.a ffmpeg_fas.o seek_indices.o 10 | -------------------------------------------------------------------------------- /ffmpeg_fas.c: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * Copyright 2008. Pittsburgh Pattern Recognition, Inc. 3 | * 4 | * This file is part of the Frame Accurate Seeking extension library to 5 | * ffmpeg (ffmpeg-fas). 6 | * 7 | * ffmpeg-fas is free software; you can redistribute it and/or modify it 8 | * under the terms of the GNU Lesser General Public License as published by 9 | * the Free Software Foundation; either version 3 of the License, or (at your 10 | * option) any later version. 11 | * 12 | * The ffmpeg-fas library is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 14 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 15 | * License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public License 18 | * along with the ffmpeg-fas library. If not, see . 19 | * 20 | ******************************************************************************/ 21 | 22 | #include "ffmpeg_fas.h" 23 | 24 | #if defined( _WIN32 ) && defined( STATIC_DLL ) 25 | extern "C" 26 | { 27 | #include "libavformat/avformat.h" 28 | #include "libavcodec/avcodec.h" 29 | int img_convert(AVPicture *dst, int dst_pix_fmt, const AVPicture *src, int src_pix_fmt, int src_width, int src_height); 30 | } 31 | #else 32 | #include "libavformat/avformat.h" 33 | #include "libavcodec/avcodec.h" 34 | #endif /* _WIN32 && STATIC_DLL */ 35 | 36 | #include "seek_indices.h" 37 | #include "private_errors.h" 38 | 39 | #include 40 | #include 41 | #include 42 | #include 43 | 44 | #define FIRST_FRAME_INDEX 0 45 | #define NUM_POSSIBLE_ERRORS 9 46 | 47 | enum PixelFormat fmt; 48 | 49 | /**** Private Types ***********************************************************/ 50 | 51 | typedef struct fas_context_struct { 52 | fas_boolean_type is_video_active; 53 | fas_boolean_type is_frame_available; 54 | 55 | int current_frame_index; 56 | 57 | seek_table_type seek_table; 58 | 59 | /* ffmpeg */ 60 | AVFormatContext *format_context; 61 | AVCodecContext *codec_context; 62 | int stream_idx; 63 | 64 | AVFrame *frame_buffer; // internal buffer 65 | 66 | AVFrame *rgb_frame_buffer; // extra AVFrames (for color conversion) 67 | uint8_t *rgb_buffer; // actual data buffer for rgb_frame_buffer (needs to be freed seperately) 68 | fas_boolean_type rgb_already_converted; // color_convert(frame_buffer) == rgb_frame_buffer (so we don't need to repeat conversions) 69 | 70 | AVFrame *gray8_frame_buffer; 71 | uint8_t *gray8_buffer; 72 | fas_boolean_type gray8_already_converted; 73 | 74 | int64_t current_dts; // decoding timestamp of the most recently parsed packet 75 | int64_t previous_dts; // for previous packet (always use previous packet for seek_table (workaround)) 76 | int64_t keyframe_packet_dts; // dts of most recent keyframe packet 77 | int64_t first_dts; // for very first packet (needed in seek, for first keyframe) 78 | 79 | } fas_context_type; 80 | 81 | static char* invalid_error_code = "not a valid error code"; 82 | static char *gbl_error_strings[NUM_POSSIBLE_ERRORS] = 83 | { 84 | "fas_success", 85 | "fas_failure", 86 | "fas_invalid_argument", 87 | "fas_out_of_memory", 88 | "fas_unsupported_format", 89 | "fas_unsupported_codec", 90 | "fas_no_more_frames", 91 | "fas_decoding_error", 92 | "fas_seek_error" 93 | }; 94 | 95 | char* fas_error_message(fas_error_type error) 96 | { 97 | if ((error < 0) || (error >= NUM_POSSIBLE_ERRORS)) 98 | return invalid_error_code; 99 | 100 | return gbl_error_strings[error]; 101 | } 102 | 103 | static void private_show_warning (const char *message); 104 | static fas_error_type private_show_error (const char *message, fas_error_type error); 105 | static fas_error_type private_convert_to_rgb (fas_context_ref_type ctx); 106 | static fas_error_type private_seek_to_nearest_key (fas_context_ref_type context, int target_index, int offset); 107 | fas_error_type private_complete_seek_table (fas_context_ref_type context); 108 | 109 | 110 | void fas_set_logging (fas_boolean_type logging) 111 | { 112 | if (logging == FAS_TRUE) 113 | { 114 | SHOW_ERROR_MESSAGES = 1; 115 | SHOW_WARNING_MESSAGES = 1; 116 | #ifndef _WIN32 117 | av_log_level = AV_LOG_INFO; 118 | #endif 119 | } 120 | else 121 | { 122 | SHOW_ERROR_MESSAGES = 0; 123 | SHOW_WARNING_MESSAGES = 0; 124 | #ifndef _WIN32 125 | av_log_level = AV_LOG_QUIET; 126 | #endif 127 | } 128 | } 129 | 130 | /* Set the output image colorspace */ 131 | void fas_set_format(fas_color_space_type format) 132 | { 133 | switch (format) 134 | { 135 | case FAS_GRAY8: 136 | fmt = PIX_FMT_GRAY8; 137 | break; 138 | case FAS_ARGB32: 139 | fmt = PIX_FMT_RGB32_1; 140 | break; 141 | case FAS_ABGR32: 142 | fmt = PIX_FMT_BGR32_1; 143 | break; 144 | case FAS_YUV420P: 145 | fmt = PIX_FMT_YUV420P; 146 | break; 147 | case FAS_YUYV422: 148 | fmt = PIX_FMT_YUYV422; 149 | break; 150 | case FAS_UYVY422: 151 | fmt = PIX_FMT_UYVY422; 152 | break; 153 | case FAS_YUV422P: 154 | fmt = PIX_FMT_YUV422P; 155 | break; 156 | case FAS_YUV444P: 157 | fmt = PIX_FMT_YUV444P; 158 | break; 159 | case FAS_RGB24: 160 | fmt = PIX_FMT_RGB24; 161 | break; 162 | case FAS_BGR24: 163 | fmt = PIX_FMT_BGR24; 164 | break; 165 | default: 166 | fmt = PIX_FMT_RGB24; 167 | break; 168 | } 169 | } 170 | 171 | 172 | void fas_initialize (fas_boolean_type logging, fas_color_space_type format) 173 | { 174 | fas_set_logging(logging); 175 | fas_set_format(format); 176 | av_register_all(); 177 | 178 | return; 179 | } 180 | 181 | /* fas_open_video */ 182 | 183 | fas_error_type fas_open_video (fas_context_ref_type *context_ptr, char *file_path) 184 | { 185 | if (NULL == context_ptr) 186 | return private_show_error ("NULL context pointer provided", FAS_INVALID_ARGUMENT); 187 | 188 | // seek_error_type seek_error; 189 | fas_context_ref_type fas_context; 190 | 191 | *context_ptr = NULL; // set returned context to NULL in case of error 192 | 193 | fas_context = (fas_context_ref_type)malloc (sizeof (fas_context_type)); 194 | memset(fas_context, 0, sizeof(fas_context_type)); 195 | 196 | if (NULL == fas_context) 197 | return private_show_error ("unable to allocate buffer", FAS_OUT_OF_MEMORY); 198 | 199 | fas_context->is_video_active = FAS_TRUE; 200 | fas_context->is_frame_available = FAS_TRUE; 201 | fas_context->current_frame_index = FIRST_FRAME_INDEX - 1; 202 | fas_context->current_dts = AV_NOPTS_VALUE; 203 | fas_context->previous_dts = AV_NOPTS_VALUE; 204 | fas_context->keyframe_packet_dts = AV_NOPTS_VALUE; 205 | fas_context->first_dts = AV_NOPTS_VALUE; 206 | 207 | fas_context->seek_table = seek_init_table (-1); /* default starting size */ 208 | 209 | if (av_open_input_file ( &(fas_context->format_context), file_path, NULL, 0, NULL ) != 0) 210 | { 211 | fas_close_video(fas_context); 212 | return private_show_error ("failure to open file", FAS_UNSUPPORTED_FORMAT); 213 | } 214 | 215 | if (av_find_stream_info (fas_context->format_context) < 0) 216 | { 217 | fas_close_video(fas_context); 218 | return private_show_error ("could not extract stream information", FAS_UNSUPPORTED_FORMAT); 219 | } 220 | 221 | if (SHOW_WARNING_MESSAGES) 222 | dump_format(fas_context->format_context, 0, file_path, 0); 223 | 224 | int stream_idx; 225 | for (stream_idx = 0; stream_idx < fas_context->format_context->nb_streams; stream_idx++) 226 | { 227 | if (fas_context->format_context->streams[stream_idx]->codec->codec_type == CODEC_TYPE_VIDEO) 228 | { 229 | fas_context->stream_idx = stream_idx; 230 | fas_context->codec_context = fas_context->format_context->streams[stream_idx]->codec; 231 | break; 232 | } 233 | } 234 | 235 | if (fas_context->codec_context == 0) 236 | { 237 | fas_close_video(fas_context); 238 | return private_show_error ("failure to find a video stream", FAS_UNSUPPORTED_FORMAT); 239 | } 240 | 241 | AVCodec *codec = avcodec_find_decoder (fas_context->codec_context->codec_id); 242 | 243 | if (!codec) 244 | { 245 | fas_context->codec_context = 0; 246 | fas_close_video(fas_context); 247 | return private_show_error("failed to find correct video codec", FAS_UNSUPPORTED_CODEC); 248 | } 249 | 250 | if (avcodec_open (fas_context->codec_context, codec) < 0) 251 | { 252 | fas_context->codec_context = 0; 253 | fas_close_video(fas_context); 254 | return private_show_error ("failed to open codec", FAS_UNSUPPORTED_CODEC); 255 | } 256 | 257 | fas_context->frame_buffer = avcodec_alloc_frame (); 258 | if (fas_context->frame_buffer == NULL) 259 | { 260 | fas_close_video(fas_context); 261 | return private_show_error ("failed to allocate frame buffer", FAS_OUT_OF_MEMORY); 262 | } 263 | 264 | fas_context->rgb_frame_buffer = avcodec_alloc_frame (); 265 | if (fas_context->rgb_frame_buffer == NULL) 266 | { 267 | fas_close_video(fas_context); 268 | return private_show_error ("failed to allocate rgb frame buffer", FAS_OUT_OF_MEMORY); 269 | } 270 | 271 | fas_context->gray8_frame_buffer = avcodec_alloc_frame (); 272 | if (fas_context->gray8_frame_buffer == NULL) 273 | { 274 | fas_close_video(fas_context); 275 | return private_show_error ("failed to allocate gray8 frame buffer", FAS_OUT_OF_MEMORY); 276 | } 277 | 278 | fas_context->rgb_buffer = 0; 279 | fas_context->gray8_buffer = 0; 280 | fas_context->rgb_already_converted = FAS_FALSE; 281 | fas_context->gray8_already_converted = FAS_FALSE; 282 | 283 | *context_ptr = fas_context; 284 | 285 | 286 | if (FAS_SUCCESS != fas_step_forward(*context_ptr)) 287 | return private_show_error ("failure decoding first frame", FAS_NO_MORE_FRAMES); 288 | 289 | if (!fas_frame_available(*context_ptr)) 290 | return private_show_error ("couldn't find a first frame (no valid frames in video stream)", FAS_NO_MORE_FRAMES); 291 | 292 | 293 | 294 | return FAS_SUCCESS; 295 | } 296 | 297 | /* fas_close_video */ 298 | fas_error_type fas_close_video (fas_context_ref_type context) 299 | { 300 | if (NULL == context) 301 | return private_show_error ("NULL context provided for fas_close_video()", FAS_INVALID_ARGUMENT); 302 | 303 | if (!(context->is_video_active)) 304 | { 305 | private_show_warning ("Redundant attempt to close an inactive video"); 306 | return FAS_SUCCESS; 307 | } 308 | 309 | if (context->codec_context) 310 | if (avcodec_find_decoder (context->codec_context->codec_id)) 311 | avcodec_close(context->codec_context); 312 | 313 | if (context->format_context) 314 | av_close_input_file (context->format_context); 315 | 316 | if (context->rgb_frame_buffer) 317 | av_free (context->rgb_frame_buffer); 318 | 319 | if (context->gray8_frame_buffer) 320 | av_free (context->gray8_frame_buffer); 321 | 322 | if (context->rgb_buffer) 323 | av_free(context->rgb_buffer); 324 | 325 | if (context->gray8_buffer) 326 | av_free(context->gray8_buffer); 327 | 328 | if (context->frame_buffer) 329 | av_free (context->frame_buffer); 330 | 331 | seek_release_table (&(context->seek_table)); 332 | 333 | context->is_video_active = FAS_FALSE; 334 | 335 | free (context); 336 | 337 | return FAS_SUCCESS; 338 | } 339 | 340 | 341 | /* fas_step_forward */ 342 | fas_error_type fas_step_forward (fas_context_ref_type context) 343 | { 344 | if ((NULL == context) || (FAS_TRUE != context->is_video_active)) { 345 | return private_show_error ("invalid or unopened context", FAS_INVALID_ARGUMENT); 346 | } 347 | 348 | if (!context->is_frame_available) 349 | { 350 | private_show_warning ("tried to advance after end of frames"); 351 | return FAS_SUCCESS; 352 | } 353 | 354 | context->current_frame_index++; 355 | 356 | AVPacket packet; 357 | while (FAS_TRUE) 358 | { 359 | if (av_read_frame(context->format_context, &packet) < 0) 360 | { 361 | /* finished */ 362 | context->is_frame_available = FAS_FALSE; 363 | context->seek_table.completed = seek_true; 364 | return FAS_SUCCESS; 365 | } 366 | 367 | int frameFinished; 368 | if (packet.stream_index == context->stream_idx) 369 | { 370 | context->previous_dts = context->current_dts; 371 | context->current_dts = packet.dts; 372 | 373 | /* seek support: set first_dts */ 374 | if (context->first_dts == AV_NOPTS_VALUE) 375 | context->first_dts = packet.dts; 376 | 377 | /* seek support: set key-packet info to previous packet's dts, when possible */ 378 | /* note this -1 approach to setting the packet is a workaround for a common failure. setting 379 | to 0 would work just incur a huge penalty in videos that needed -1. Might be worth testing. 380 | */ 381 | if (packet.flags & PKT_FLAG_KEY) 382 | { 383 | //fprintf(stderr, "Packet: (F:%d %lld %lld)\n", context->current_frame_index, packet.pts, packet.dts); 384 | 385 | if (context->previous_dts == AV_NOPTS_VALUE) 386 | context->keyframe_packet_dts = packet.dts; 387 | else 388 | context->keyframe_packet_dts = context->previous_dts; 389 | } 390 | 391 | avcodec_decode_video(context->codec_context, context->frame_buffer, &frameFinished, 392 | packet.data, packet.size); 393 | 394 | if (frameFinished) 395 | { 396 | /* seek support: (try to) add entry to seek_table */ 397 | if (context->frame_buffer->key_frame) 398 | { 399 | // fprintf(stderr, "Frame : (PXX F%d: %lld %lld)\n", context->current_frame_index, packet.pts, packet.dts); 400 | 401 | seek_entry_type entry; 402 | entry.display_index = context->current_frame_index; 403 | entry.first_packet_dts = context->keyframe_packet_dts; 404 | entry.last_packet_dts = packet.dts; 405 | 406 | if (fas_get_frame_index(context) == FIRST_FRAME_INDEX) 407 | entry.first_packet_dts = context->first_dts; 408 | 409 | seek_append_table_entry(&context->seek_table, entry); 410 | } 411 | 412 | if (context->current_frame_index - FIRST_FRAME_INDEX + 1 > context->seek_table.num_frames) 413 | context->seek_table.num_frames = context->current_frame_index - FIRST_FRAME_INDEX + 1; 414 | 415 | break; 416 | } 417 | } 418 | 419 | av_free_packet(&packet); 420 | } 421 | 422 | context->rgb_already_converted = FAS_FALSE; 423 | context->gray8_already_converted = FAS_FALSE; 424 | av_free_packet(&packet); 425 | return FAS_SUCCESS; 426 | } 427 | 428 | /* fas_get_frame_index */ 429 | 430 | int fas_get_frame_index (fas_context_ref_type context) 431 | { 432 | if (NULL == context) 433 | return private_show_error ("NULL context provided for fas_get_frame_index()", FAS_INVALID_ARGUMENT); 434 | 435 | if (FAS_TRUE != context->is_video_active) 436 | return private_show_error ("No video is open for fas_get_frame_index()", FAS_INVALID_ARGUMENT); 437 | 438 | return context->current_frame_index; 439 | } 440 | 441 | 442 | /* fas_get_frame */ 443 | 444 | fas_error_type fas_get_frame (fas_context_ref_type context, fas_raw_image_type *image_ptr) 445 | { 446 | int buffer_size; 447 | fas_error_type fas_error; 448 | 449 | if (NULL == context || FAS_FALSE == context->is_video_active) 450 | return private_show_error ("null context or inactive video", FAS_INVALID_ARGUMENT); 451 | 452 | if (NULL == image_ptr) 453 | return private_show_error ("null image_ptr on get_frame", FAS_INVALID_ARGUMENT); 454 | 455 | if (!fas_frame_available(context)) 456 | return private_show_error ("no frame available for extraction", FAS_NO_MORE_FRAMES); 457 | 458 | memset (image_ptr, 0, sizeof (fas_raw_image_type)); 459 | 460 | switch (fmt) 461 | { 462 | case PIX_FMT_RGB24: 463 | image_ptr->bytes_per_line = context->codec_context->width * 3; 464 | image_ptr->color_space = FAS_RGB24; 465 | break; 466 | case PIX_FMT_BGR24: 467 | image_ptr->bytes_per_line = context->codec_context->width * 3; 468 | image_ptr->color_space = FAS_BGR24; 469 | break; 470 | case PIX_FMT_ARGB: 471 | image_ptr->bytes_per_line = context->codec_context->width * 4; 472 | image_ptr->color_space = FAS_ARGB32; 473 | break; 474 | case PIX_FMT_ABGR: 475 | image_ptr->bytes_per_line = context->codec_context->width * 4; 476 | image_ptr->color_space = FAS_ABGR32; 477 | break; 478 | case PIX_FMT_YUV420P: 479 | image_ptr->bytes_per_line = (context->codec_context->width * 3) >> 1; 480 | image_ptr->color_space = FAS_YUV420P; 481 | break; 482 | case PIX_FMT_YUYV422: 483 | image_ptr->bytes_per_line = context->codec_context->width * 2; 484 | image_ptr->color_space = FAS_YUYV422; 485 | break; 486 | case PIX_FMT_UYVY422: 487 | image_ptr->bytes_per_line = context->codec_context->width * 2; 488 | image_ptr->color_space = FAS_UYVY422; 489 | break; 490 | case PIX_FMT_YUV422P: 491 | image_ptr->bytes_per_line = context->codec_context->width * 2; 492 | image_ptr->color_space = FAS_YUV422P; 493 | break; 494 | case PIX_FMT_YUV444P: 495 | image_ptr->bytes_per_line = context->codec_context->width * 3; 496 | image_ptr->color_space = FAS_YUV444P; 497 | break; 498 | } 499 | 500 | buffer_size = image_ptr->bytes_per_line * context->codec_context->height; 501 | 502 | image_ptr->data = (unsigned char *)malloc (buffer_size); 503 | if (NULL == image_ptr->data) 504 | return private_show_error ("unable to allocate space for RGB image", FAS_OUT_OF_MEMORY); 505 | 506 | image_ptr->width = context->codec_context->width; 507 | image_ptr->height = context->codec_context->height; 508 | 509 | 510 | fas_error = private_convert_to_rgb(context); 511 | 512 | int j; 513 | unsigned char *from; 514 | unsigned char *to; 515 | for (j=0;jcodec_context->height; j++) 516 | { 517 | from = context->rgb_frame_buffer->data[0] + j*context->rgb_frame_buffer->linesize[0]; 518 | to = image_ptr->data + j*image_ptr->bytes_per_line; 519 | 520 | memcpy(to, from, image_ptr->bytes_per_line); 521 | } 522 | 523 | if (FAS_SUCCESS != fas_error) 524 | return private_show_error ("unable to convert image to RGB", FAS_FAILURE); 525 | 526 | return FAS_SUCCESS; 527 | } 528 | 529 | /* fas_free_frame */ 530 | 531 | void fas_free_frame (fas_raw_image_type image) 532 | { 533 | if (NULL == image.data) 534 | return; 535 | 536 | free (image.data); 537 | 538 | return; 539 | } 540 | 541 | /* fas_get_seek_table */ 542 | seek_table_type fas_get_seek_table (fas_context_ref_type context) 543 | { 544 | seek_table_type null_table; 545 | 546 | null_table.array = NULL; 547 | null_table.completed = seek_false; 548 | null_table.num_frames = -1; 549 | null_table.num_entries = 0; 550 | null_table.allocated_size = 0; 551 | 552 | if (NULL == context || FAS_FALSE == context->is_video_active) 553 | return null_table; 554 | 555 | return context->seek_table; 556 | } 557 | 558 | /* fas_put_seek_table */ 559 | fas_error_type fas_put_seek_table (fas_context_ref_type context, seek_table_type table) 560 | { 561 | if (NULL == context || FAS_FALSE == context->is_video_active) 562 | return private_show_error ("null context or inactive video", FAS_INVALID_ARGUMENT); 563 | 564 | seek_release_table (&context->seek_table); 565 | context->seek_table = seek_copy_table(table); 566 | 567 | return FAS_SUCCESS; 568 | } 569 | 570 | /* private_complete_seek_table */ 571 | fas_error_type private_complete_seek_table (fas_context_ref_type context) 572 | { 573 | if ((NULL == context) || (FAS_FALSE == context->is_video_active)) 574 | return private_show_error ("invalid or unopened context", FAS_INVALID_ARGUMENT); 575 | 576 | if (context->seek_table.completed) 577 | return FAS_SUCCESS; 578 | 579 | fas_error_type fas_error = fas_seek_to_nearest_key (context, context->seek_table.num_frames + FIRST_FRAME_INDEX - 1); 580 | if (FAS_SUCCESS != fas_error) 581 | return private_show_error("failed when trying to complete seek table (1) (first frame not labeled keyframe?)", fas_error); 582 | 583 | while (fas_frame_available(context)) 584 | { 585 | // printf("%d\n", context->seek_table.num_frames); 586 | fas_step_forward(context); 587 | } 588 | 589 | if (!context->seek_table.completed) 590 | return private_show_error("failed when trying to complete seek table (2)", FAS_SEEK_ERROR); 591 | 592 | return FAS_SUCCESS; 593 | } 594 | 595 | /* fas_seek_to_frame */ 596 | fas_error_type fas_seek_to_frame (fas_context_ref_type context, int target_index) 597 | { 598 | 599 | fas_error_type fas_error; 600 | 601 | if ((NULL == context) || (FAS_FALSE == context->is_video_active)) 602 | return private_show_error ("invalid or unopened context", FAS_INVALID_ARGUMENT); 603 | 604 | // printf("seeking to %d (from %d)!\n", target_index, context->current_frame_index); 605 | if (target_index == context->current_frame_index) 606 | return FAS_SUCCESS; 607 | 608 | fas_error = fas_seek_to_nearest_key (context, target_index); 609 | 610 | if (fas_error != FAS_SUCCESS) 611 | return private_show_error ("error advancing to key frame before seek", fas_error); 612 | 613 | if (fas_get_frame_index(context) > target_index) 614 | return private_show_error ("error advancing to key frame before seek (index isn't right)", fas_error); 615 | 616 | while (fas_get_frame_index(context) < target_index) 617 | { 618 | if (fas_frame_available(context)) 619 | fas_step_forward(context); 620 | else 621 | return private_show_error ("error advancing to request frame (probably out of range)", FAS_SEEK_ERROR); 622 | } 623 | 624 | 625 | return FAS_SUCCESS; 626 | } 627 | 628 | /* fas_seek_to_nearest_key */ 629 | 630 | fas_error_type fas_seek_to_nearest_key (fas_context_ref_type context, int target_index) 631 | { 632 | return private_seek_to_nearest_key(context, target_index,0); 633 | } 634 | 635 | /* private_seek_to_nearest_key */ 636 | 637 | fas_error_type private_seek_to_nearest_key (fas_context_ref_type context, int target_index, int offset) 638 | { 639 | if ((NULL == context) || (FAS_TRUE != context->is_video_active)) 640 | return private_show_error ("invalid or unopened context", FAS_INVALID_ARGUMENT); 641 | 642 | // printf("HERE: from: %d to: %d offset: %d\n", context->current_frame_index, target_index, offset); 643 | fas_error_type fas_error; 644 | seek_entry_type seek_entry; 645 | seek_error_type seek_error = seek_get_nearest_entry (&(context->seek_table), &seek_entry, target_index, offset); 646 | 647 | if (seek_error != seek_no_error) 648 | return private_show_error ("error while searching seek table", FAS_SEEK_ERROR); 649 | 650 | if (seek_entry.display_index == context->current_frame_index) 651 | return FAS_SUCCESS; 652 | 653 | // printf("HERE: from: %d to: %d (%d) offset: %d\n", context->current_frame_index, target_index, seek_entry.display_index, offset); 654 | // printf("trying to seek to %d (%lld->%lld)\n", seek_entry.display_index, seek_entry.first_packet_dts, seek_entry.last_packet_dts); 655 | 656 | // if something goes terribly wrong, return bad current_frame_index 657 | context->current_frame_index = -2; 658 | context->is_frame_available = FAS_TRUE; 659 | 660 | int flags = 0; 661 | if (seek_entry.first_packet_dts <= context->current_dts) 662 | flags = AVSEEK_FLAG_BACKWARD; 663 | 664 | // printf("av_seek_frame: %lld\n", seek_entry.first_packet_dts); 665 | if (av_seek_frame(context->format_context, context->stream_idx, seek_entry.first_packet_dts, flags) < 0) 666 | return private_show_error("seek to keyframe failed", FAS_SEEK_ERROR); 667 | 668 | 669 | avcodec_flush_buffers (context->codec_context); 670 | 671 | fas_error = fas_step_forward (context); 672 | 673 | if (fas_error != FAS_SUCCESS || !context->is_frame_available) 674 | { 675 | // something bad has happened, try previous keyframe 676 | private_show_warning("processing of seeked keyframe failed, trying previous keyframe"); 677 | return private_seek_to_nearest_key(context, target_index, offset + 1); 678 | } 679 | 680 | while (context->current_dts < seek_entry.last_packet_dts) 681 | { 682 | //printf("frame-times: current: %lld target: %lld is_key: %d\n", context->current_dts, seek_entry.last_packet_dts, context->frame_buffer->key_frame); 683 | fas_error = fas_step_forward(context); 684 | if (fas_error != FAS_SUCCESS) 685 | return private_show_error ("unable to process up to target frame (fas_seek_to_frame)", fas_error); 686 | } 687 | 688 | // printf("keyframe vitals: %d looking_for: %lld at: %lld\n", seek_entry.display_index, seek_entry.last_packet_dts, context->current_dts); 689 | if (context->current_dts != seek_entry.last_packet_dts) 690 | { 691 | /* seek to last key-frame, but look for this one */ 692 | private_show_warning("missed keyframe, trying previous keyframe"); 693 | return private_seek_to_nearest_key(context, target_index, offset + 1); 694 | } 695 | 696 | /* Ideally, we could just check if the frame decoded is of the correct time stamp... but... we need several ugly workarounds: 697 | 698 | 1) Some videos have bad keyframes that don't get decoded properly. In this cases, we need to go back a keyframe. 699 | 700 | 2) Other times, none of the frames are labeled keyframes. In these cases, we need to allow seeking to frame 0 701 | even when it's not labeled as a keyframe. Messy set of conditions. 702 | */ 703 | 704 | if ((!context->frame_buffer->key_frame) && (seek_entry.display_index != 0)) 705 | { 706 | private_show_warning("found keyframe, but not labeled as keyframe, so trying previous keyframe."); 707 | /* seek & look for previous keyframe */ 708 | /* REMOVE FROM TABLE? */ 709 | return private_seek_to_nearest_key(context, seek_entry.display_index - 1, 0); 710 | } 711 | 712 | context->current_frame_index = seek_entry.display_index; 713 | 714 | return FAS_SUCCESS; 715 | } 716 | 717 | /* fas_get_frame_count */ 718 | 719 | int fas_get_frame_count_fast (fas_context_ref_type context) 720 | { 721 | 722 | if (NULL == context || FAS_FALSE == context->is_video_active) 723 | { 724 | private_show_error ("NULL or invalid context", FAS_INVALID_ARGUMENT); 725 | return -1; 726 | } 727 | 728 | if (context->seek_table.completed == seek_true) 729 | return context->seek_table.num_frames; 730 | 731 | return -1; 732 | } 733 | 734 | int fas_get_frame_count (fas_context_ref_type context) 735 | { 736 | int fast = fas_get_frame_count_fast(context); 737 | if (fast >= 0) 738 | return fast; 739 | 740 | int current_frame = fas_get_frame_index(context); 741 | 742 | fas_error_type fas_error; 743 | 744 | fas_error = private_complete_seek_table(context); 745 | if (FAS_SUCCESS != fas_error) 746 | { 747 | private_show_error("failed in get_frame_count trying to complete the seek table", fas_error); 748 | return -1; 749 | } 750 | 751 | // seek_show_raw_table(stderr, context->seek_table); 752 | 753 | fas_error = fas_seek_to_frame(context, current_frame); 754 | if (FAS_SUCCESS != fas_error) 755 | { 756 | private_show_error("failed in get_frame_count when trying to seek back to original location", fas_error); 757 | return -1; 758 | } 759 | 760 | fast = fas_get_frame_count_fast(context); 761 | if (fast < 0) 762 | private_show_warning("get_frame_count failed"); 763 | 764 | return fast; 765 | } 766 | 767 | /* fas_frame_available */ 768 | 769 | fas_boolean_type fas_frame_available (fas_context_ref_type context) 770 | { 771 | if (NULL == context) 772 | { 773 | private_show_error ("NULL context provided for fas_get_frame_index()", FAS_INVALID_ARGUMENT); 774 | return FAS_FALSE; 775 | } 776 | 777 | if (!context->is_video_active) 778 | return FAS_FALSE; 779 | 780 | return context->is_frame_available; 781 | } 782 | 783 | 784 | /* private_show_error */ 785 | 786 | static fas_error_type private_show_error (const char *message, fas_error_type error) 787 | { 788 | if (SHOW_ERROR_MESSAGES) 789 | fprintf (stderr, " ===> ffmpeg_fas: %s\n", message); 790 | return error; 791 | } 792 | 793 | static void private_show_warning (const char *message) 794 | { 795 | if (SHOW_WARNING_MESSAGES) 796 | fprintf (stderr, " ---- ffmpeg_fas: %s\n", message); 797 | return; 798 | } 799 | 800 | 801 | /* private_convert_to_rgb */ 802 | 803 | fas_error_type private_convert_to_rgb (fas_context_ref_type ctx) 804 | { 805 | if (ctx->rgb_already_converted) 806 | return FAS_SUCCESS; 807 | 808 | if (ctx->rgb_buffer == 0) 809 | { 810 | int numBytes = avpicture_get_size(fmt, ctx->codec_context->width, 811 | ctx->codec_context->height); 812 | ctx->rgb_buffer = (uint8_t *) av_malloc(numBytes*sizeof(uint8_t)); 813 | avpicture_fill((AVPicture *) ctx->rgb_frame_buffer, ctx->rgb_buffer, fmt, 814 | ctx->codec_context->width, ctx->codec_context->height); 815 | } 816 | 817 | if (img_convert((AVPicture *) ctx->rgb_frame_buffer, fmt, (AVPicture *) ctx->frame_buffer, 818 | ctx->codec_context->pix_fmt, 819 | ctx->codec_context->width, ctx->codec_context->height) < 0) 820 | private_show_error("error converting to rgb", FAS_DECODING_ERROR); 821 | 822 | ctx->rgb_already_converted = FAS_TRUE; 823 | 824 | return FAS_SUCCESS; 825 | } 826 | 827 | 828 | /* private_convert_to_gray8 */ 829 | 830 | fas_error_type private_convert_to_gray8 (fas_context_ref_type ctx) 831 | { 832 | if (ctx->gray8_already_converted) 833 | return FAS_SUCCESS; 834 | 835 | if (ctx->gray8_buffer == 0) 836 | { 837 | int numBytes = avpicture_get_size(PIX_FMT_GRAY8, ctx->codec_context->width, 838 | ctx->codec_context->height); 839 | ctx->gray8_buffer = (uint8_t *) av_malloc(numBytes*sizeof(uint8_t)); 840 | avpicture_fill((AVPicture *) ctx->gray8_frame_buffer, ctx->gray8_buffer, PIX_FMT_GRAY8, 841 | ctx->codec_context->width, ctx->codec_context->height); 842 | } 843 | 844 | if (img_convert((AVPicture *) ctx->gray8_frame_buffer, PIX_FMT_GRAY8, (AVPicture *) ctx->frame_buffer, 845 | ctx->codec_context->pix_fmt, 846 | ctx->codec_context->width, ctx->codec_context->height) < 0) 847 | private_show_error("error converting to gray8", FAS_DECODING_ERROR); 848 | 849 | ctx->gray8_already_converted = FAS_TRUE; 850 | 851 | return FAS_SUCCESS; 852 | } 853 | 854 | int fas_get_current_width(fas_context_ref_type context) 855 | { 856 | return context->codec_context->width; 857 | } 858 | 859 | int fas_get_current_height(fas_context_ref_type context) 860 | { 861 | return context->codec_context->height; 862 | } 863 | 864 | unsigned long long fas_get_frame_duration(fas_context_ref_type context) 865 | { 866 | if (context->format_context->streams[context->stream_idx]->time_base.den != context->format_context->streams[context->stream_idx]->r_frame_rate.num 867 | || context->format_context->streams[context->stream_idx]->time_base.num != context->format_context->streams[context->stream_idx]->r_frame_rate.den) 868 | { 869 | double frac = (double)(context->format_context->streams[context->stream_idx]->r_frame_rate.den) / (double)(context->format_context->streams[context->stream_idx]->r_frame_rate.num); 870 | return (unsigned long long)(frac*10000000.); 871 | } 872 | else 873 | { 874 | return (unsigned long long)(((double)(context->format_context->streams[context->stream_idx]->time_base.num)) 875 | /((double)(context->format_context->streams[context->stream_idx]->time_base.den))*10000000.); 876 | } 877 | } 878 | 879 | fas_error_type fas_fill_gray8_ptr(fas_context_ref_type context, unsigned char *y) 880 | { 881 | /* this conversion also seems to screw up sometimes -- pal8 -> gray8? legodragon.avi */ 882 | if (private_convert_to_gray8(context) != FAS_SUCCESS) 883 | return FAS_FAILURE; 884 | 885 | int width = context->codec_context->width; 886 | int height = context->codec_context->height; 887 | int i; 888 | for (i=0;i < height; i++) 889 | memcpy(y + width * i, context->gray8_frame_buffer->data[0] + context->gray8_frame_buffer->linesize[0] * i, width); 890 | 891 | return FAS_SUCCESS; 892 | } 893 | 894 | fas_error_type fas_fill_420p_ptrs (fas_context_ref_type context, unsigned char *y, unsigned char *u, unsigned char *v) 895 | { 896 | AVFrame *p = context->frame_buffer; 897 | 898 | /* 411p to 420p conversion fails!? ... so i left this -ldb */ 899 | if (context->codec_context->pix_fmt != PIX_FMT_YUV420P) 900 | return FAS_FAILURE; 901 | 902 | int width = context->codec_context->width; 903 | int height = context->codec_context->height; 904 | int i; 905 | for (i=0;i < height / 2; i++) 906 | { 907 | memcpy(y + width * (2*i) , p->data[0] + p->linesize[0] * (2*i) , width); 908 | memcpy(y + width * (2*i + 1), p->data[0] + p->linesize[0] * (2*i + 1), width); 909 | memcpy(u + width / 2 * i, p->data[1] + p->linesize[1] * i, width / 2); 910 | memcpy(v + width / 2 * i, p->data[2] + p->linesize[2] * i, width / 2); 911 | } 912 | 913 | return FAS_SUCCESS; 914 | } 915 | -------------------------------------------------------------------------------- /ffmpeg_fas.def: -------------------------------------------------------------------------------- 1 | LIBRARY ffmpeg_fas 2 | EXPORTS 3 | fas_initialize 4 | fas_open_video 5 | fas_close_video 6 | fas_free_frame 7 | fas_get_frame 8 | fas_get_frame_index 9 | fas_get_frame_duration 10 | fas_step_forward 11 | fas_seek_to_frame 12 | fas_get_frame_count 13 | fas_get_current_height 14 | fas_get_current_width 15 | -------------------------------------------------------------------------------- /ffmpeg_fas.h: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * Copyright 2008. Pittsburgh Pattern Recognition, Inc. 3 | * 4 | * This file is part of the Frame Accurate Seeking extension library to 5 | * ffmpeg (ffmpeg-fas). 6 | * 7 | * ffmpeg-fas is free software; you can redistribute it and/or modify it 8 | * under the terms of the GNU Lesser General Public License as published by 9 | * the Free Software Foundation; either version 3 of the License, or (at your 10 | * option) any later version. 11 | * 12 | * The ffmpeg-fas library is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 14 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 15 | * License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public License 18 | * along with the ffmpeg-fas library. If not, see . 19 | * 20 | ******************************************************************************/ 21 | 22 | #ifndef FFMPEG_FAS_H 23 | #define FFMPEG_FAS_H 24 | 25 | /* If C++ then we need to __extern "C". Compiler defines __cplusplus */ 26 | #ifdef __cplusplus 27 | #define __extern extern "C" 28 | #else 29 | #define __extern extern 30 | #endif 31 | 32 | #include "seek_indices.h" 33 | 34 | 35 | typedef enum 36 | { 37 | FAS_GRAY8 = 1, 38 | FAS_RGB24 = 2, 39 | FAS_BGR24 = 3, 40 | FAS_ARGB32 = 4, 41 | FAS_ABGR32 = 5, 42 | FAS_YUV420P = 6, 43 | FAS_YUYV422 = 7, 44 | FAS_UYVY422 = 8, 45 | FAS_YUV422P = 9, 46 | FAS_YUV444P = 10, 47 | } fas_color_space_type; 48 | 49 | typedef struct 50 | { 51 | unsigned char *data; 52 | int width; 53 | int height; 54 | int bytes_per_line; 55 | fas_color_space_type color_space; 56 | } fas_raw_image_type; 57 | 58 | 59 | /********************************************************************** 60 | * Video IO Types 61 | **********************************************************************/ 62 | 63 | typedef struct fas_context_struct* fas_context_ref_type; 64 | 65 | typedef enum 66 | { 67 | FAS_SUCCESS, 68 | FAS_FAILURE, 69 | FAS_INVALID_ARGUMENT, 70 | FAS_OUT_OF_MEMORY, 71 | FAS_UNSUPPORTED_FORMAT, 72 | FAS_UNSUPPORTED_CODEC, 73 | FAS_NO_MORE_FRAMES, 74 | FAS_DECODING_ERROR, 75 | FAS_SEEK_ERROR, 76 | } fas_error_type; 77 | 78 | typedef enum 79 | { 80 | FAS_FALSE = 0, 81 | FAS_TRUE = 1 82 | } fas_boolean_type; 83 | 84 | 85 | __extern void fas_initialize (fas_boolean_type logging, fas_color_space_type format); 86 | __extern void fas_set_format (fas_color_space_type format); 87 | 88 | __extern fas_error_type fas_open_video (fas_context_ref_type *context_ptr, char *file_path); 89 | __extern fas_error_type fas_close_video (fas_context_ref_type context); 90 | 91 | __extern char* fas_error_message (fas_error_type error); 92 | 93 | __extern fas_boolean_type fas_frame_available (fas_context_ref_type context); 94 | __extern int fas_get_frame_index (fas_context_ref_type context); 95 | __extern fas_error_type fas_step_forward (fas_context_ref_type context); 96 | 97 | __extern fas_error_type fas_get_frame (fas_context_ref_type context, fas_raw_image_type *image_ptr); 98 | __extern void fas_free_frame (fas_raw_image_type image); 99 | 100 | __extern fas_error_type fas_seek_to_nearest_key (fas_context_ref_type context, int target_index); 101 | __extern fas_error_type fas_seek_to_frame (fas_context_ref_type context, int target_index); 102 | 103 | __extern int fas_get_frame_count (fas_context_ref_type context); 104 | __extern int fas_get_frame_count_fast (fas_context_ref_type context); 105 | 106 | __extern fas_error_type fas_put_seek_table (fas_context_ref_type context, seek_table_type table); 107 | __extern seek_table_type fas_get_seek_table (fas_context_ref_type context); 108 | 109 | /* will extract raw 420p if the video is in that format -- needs to be alloced ahead of time*/ 110 | __extern fas_error_type fas_fill_420p_ptrs (fas_context_ref_type context, unsigned char *y, unsigned char *u, unsigned char *v); 111 | 112 | /* will extract gray8 data from movie (will convert to ensure you get it) -- need to be alloc'ed ahead of time*/ 113 | __extern fas_error_type fas_fill_gray8_ptr(fas_context_ref_type context, unsigned char *y); 114 | 115 | __extern int fas_get_current_width(fas_context_ref_type context); 116 | __extern int fas_get_current_height(fas_context_ref_type context); 117 | 118 | __extern unsigned long long fas_get_frame_duration(fas_context_ref_type context); 119 | 120 | #endif 121 | -------------------------------------------------------------------------------- /ffmpeg_fas.vcproj: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 12 | 13 | 14 | 21 | 32 | 34 | 44 | 46 | 48 | 50 | 52 | 54 | 56 | 58 | 60 | 62 | 64 | 65 | 72 | 82 | 84 | 89 | 91 | 93 | 95 | 97 | 99 | 101 | 103 | 105 | 107 | 109 | 110 | 111 | 112 | 113 | 114 | 118 | 120 | 122 | 125 | 126 | 127 | 129 | 131 | 134 | 135 | 136 | 137 | 141 | 143 | 144 | 146 | 147 | 149 | 150 | 151 | 155 | 156 | 159 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | -------------------------------------------------------------------------------- /private_errors.h: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * Copyright 2008. Pittsburgh Pattern Recognition, Inc. 3 | * 4 | * This file is part of the Frame Accurate Seeking extension library to 5 | * ffmpeg (ffmpeg-fas). 6 | * 7 | * ffmpeg-fas is free software; you can redistribute it and/or modify it 8 | * under the terms of the GNU Lesser General Public License as published by 9 | * the Free Software Foundation; either version 3 of the License, or (at your 10 | * option) any later version. 11 | * 12 | * The ffmpeg-fas library is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 14 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 15 | * License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public License 18 | * along with the ffmpeg-fas library. If not, see . 19 | * 20 | ******************************************************************************/ 21 | 22 | #ifndef FAS_PRIVATE_ERROR_H 23 | #define FAS_PRIVATE_ERROR_H 24 | 25 | #if defined( _WIN32 ) && defined( STATIC_DLL ) 26 | static int SHOW_ERROR_MESSAGES; 27 | static int SHOW_WARNING_MESSAGES; 28 | #else 29 | int SHOW_ERROR_MESSAGES; 30 | int SHOW_WARNING_MESSAGES; 31 | #endif /* _WIN32 && STATIC_DLL */ 32 | #endif 33 | -------------------------------------------------------------------------------- /seek_indices.c: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * Copyright 2008. Pittsburgh Pattern Recognition, Inc. 3 | * 4 | * This file is part of the Frame Accurate Seeking extension library to 5 | * ffmpeg (ffmpeg-fas). 6 | * 7 | * ffmpeg-fas is free software; you can redistribute it and/or modify it 8 | * under the terms of the GNU Lesser General Public License as published by 9 | * the Free Software Foundation; either version 3 of the License, or (at your 10 | * option) any later version. 11 | * 12 | * The ffmpeg-fas library is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 14 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 15 | * License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public License 18 | * along with the ffmpeg-fas library. If not, see . 19 | * 20 | ******************************************************************************/ 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #include "seek_indices.h" 28 | #include "private_errors.h" 29 | 30 | /**** Defines *****************************************************************/ 31 | 32 | #define DEFAULT_INITIAL_SIZE 100 33 | 34 | static seek_error_type private_show_error (const char *message, seek_error_type error); 35 | static seek_error_type private_resize_table (seek_table_type *table, int new_size); 36 | 37 | 38 | /* 39 | * seek_init_table 40 | */ 41 | 42 | int compare_seek_tables(seek_table_type t1, seek_table_type t2) 43 | { 44 | int i; 45 | 46 | // printf("n_entries=(%d %d)\n", t1.num_entries, t2.num_entries); 47 | 48 | if (t1.num_entries != t2.num_entries) 49 | return 0; 50 | 51 | if (t1.completed != t2.completed) 52 | return 0; 53 | 54 | if (t1.num_frames != t2.num_frames) 55 | return 0; 56 | 57 | for (i=0;inum_entries = 0; 100 | table->num_frames = -1; 101 | table->completed = seek_false; 102 | 103 | if (NULL == table || NULL == table->array) 104 | return; 105 | 106 | free (table->array); 107 | return; 108 | } 109 | 110 | /* 111 | * seek_copy_table 112 | */ 113 | 114 | seek_table_type seek_copy_table (seek_table_type source) 115 | { 116 | seek_table_type dest; 117 | dest.num_entries = source.num_entries; 118 | dest.num_frames = source.num_frames; 119 | dest.completed = source.completed; 120 | 121 | if (NULL == source.array) 122 | { 123 | dest.array = NULL; 124 | dest.allocated_size = 0; 125 | return dest; 126 | } 127 | 128 | dest.array = (seek_entry_type *)malloc (source.num_entries * sizeof(seek_entry_type)); 129 | 130 | if (NULL == dest.array) 131 | { 132 | dest.array = NULL; 133 | dest.allocated_size = 0; 134 | return dest; 135 | } 136 | 137 | dest.allocated_size = source.num_entries; 138 | 139 | int i; 140 | for (i=0;iarray) 150 | return private_show_error("null or invalid seek table", seek_bad_argument); 151 | 152 | if (table->num_entries != 0) 153 | if (table->array[table->num_entries - 1].display_index >= entry.display_index) 154 | return seek_no_error; 155 | 156 | if (table->num_entries == table->allocated_size) 157 | { 158 | seek_error_type error = private_resize_table (table, table->num_entries * 2); 159 | if (error != seek_no_error) 160 | return private_show_error ("unable to resize seek table", error); 161 | } 162 | 163 | table->array[table->num_entries] = entry; 164 | table->num_entries++; 165 | 166 | return seek_no_error; 167 | } 168 | 169 | /* 170 | * seek_get_nearest_entry 171 | */ 172 | 173 | seek_error_type seek_get_nearest_entry (seek_table_type *table, seek_entry_type *entry, int display_index, int offset) 174 | { 175 | /* using offset>0 returns a modified seek_entry that sets the 'time-to-seek' to be $offset keyframes in the past. 176 | */ 177 | 178 | if (NULL == table || NULL == table->array || table->num_entries <= 0) { 179 | return private_show_error ("NULL or invalid seek table", seek_bad_argument); 180 | } 181 | 182 | if (NULL == entry) { 183 | return private_show_error ("NULL entry buffer (for return)", seek_bad_argument); 184 | } 185 | 186 | if (display_index < table->array[0].display_index) 187 | return private_show_error ("tried to seek to frame index before first frame", seek_bad_argument); 188 | 189 | int i; 190 | for (i=0; i < table->num_entries; i++) 191 | if (table->array[i].display_index > display_index) 192 | break; 193 | 194 | i = i-1; 195 | 196 | if (iarray[i]; 200 | (*entry).first_packet_dts = table->array[i-offset].first_packet_dts; 201 | 202 | return seek_no_error; 203 | } 204 | 205 | 206 | /* read raw file */ 207 | seek_table_type read_table_file(char *name) 208 | { 209 | seek_table_type ans = { NULL, (seek_boolean_type) 0, (seek_boolean_type) 0 }; 210 | 211 | FILE *table_file = fopen(name, "r"); 212 | if (table_file == NULL) 213 | return ans; 214 | 215 | int completed_flag; 216 | fscanf(table_file, "%d %d %d\n", &ans.num_frames, &ans.num_entries, &completed_flag); 217 | 218 | if (completed_flag == 1) 219 | ans.completed = seek_true; 220 | else 221 | ans.completed = seek_false; 222 | 223 | ans.allocated_size = ans.num_entries; 224 | ans.array = (seek_entry_type*) malloc (ans.allocated_size * sizeof(seek_entry_type)); 225 | 226 | int i; 227 | for (i=0;idisplay_index, entry->first_packet_dts, entry->last_packet_dts); 252 | } 253 | return seek_no_error; 254 | } 255 | 256 | seek_error_type seek_show_table (seek_table_type table) 257 | { 258 | seek_entry_type *entry; 259 | int index; 260 | 261 | if (NULL == table.array || table.num_entries <= 0) { 262 | return private_show_error ("NULL or invalid seek table", seek_bad_argument); 263 | } 264 | 265 | int completed_flag = 0; 266 | if (table.completed == seek_true) 267 | completed_flag = 1; 268 | 269 | fprintf (stderr, "--- Seek Table Dump ---\n"); 270 | fprintf (stderr, "n_frames: %d n_entries: %d completed: %d\n",table.num_frames, table.num_entries, completed_flag); 271 | for (index = 0; index < table.num_entries; index++) 272 | { 273 | entry = &(table.array[index]); 274 | 275 | fprintf (stderr, " %04d --> %08lld (%08lld)\n", entry->display_index, entry->first_packet_dts, entry->last_packet_dts); 276 | } 277 | 278 | fprintf (stderr, "-----------------------\n"); 279 | 280 | return seek_no_error; 281 | } 282 | 283 | /* 284 | * private_show_error 285 | */ 286 | 287 | static seek_error_type private_show_error (const char *message, seek_error_type error) 288 | { 289 | if (SHOW_ERROR_MESSAGES) 290 | fprintf (stderr, " ===> seek_indices: %s\n", message); 291 | 292 | return error; 293 | } 294 | 295 | /* 296 | * private_resize_table 297 | */ 298 | 299 | static seek_error_type private_resize_table (seek_table_type *table, int new_size) 300 | { 301 | seek_entry_type *new_array = NULL; 302 | 303 | if (table == NULL || new_size < 0) { 304 | return private_show_error ("invalid argument for private_resize_table()", seek_malloc_failed); 305 | } 306 | 307 | new_array = (seek_entry_type *)malloc (sizeof (seek_entry_type) * new_size); 308 | if (NULL == new_array) { 309 | return private_show_error ("unable to allocate more space for table", seek_malloc_failed); 310 | } 311 | 312 | memcpy (new_array, table->array, table->allocated_size * sizeof (seek_entry_type)); 313 | free (table->array); 314 | 315 | table->allocated_size = new_size; 316 | table->array = new_array; 317 | 318 | return seek_no_error; 319 | } 320 | -------------------------------------------------------------------------------- /seek_indices.h: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * Copyright 2008. Pittsburgh Pattern Recognition, Inc. 3 | * 4 | * This file is part of the Frame Accurate Seeking extension library to 5 | * ffmpeg (ffmpeg-fas). 6 | * 7 | * ffmpeg-fas is free software; you can redistribute it and/or modify it 8 | * under the terms of the GNU Lesser General Public License as published by 9 | * the Free Software Foundation; either version 3 of the License, or (at your 10 | * option) any later version. 11 | * 12 | * The ffmpeg-fas library is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 14 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 15 | * License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public License 18 | * along with the ffmpeg-fas library. If not, see . 19 | * 20 | ******************************************************************************/ 21 | 22 | #ifndef FAS_SEEK_INDICES_H 23 | #define FAS_SEEK_INDICES_H 24 | 25 | #include 26 | #include 27 | 28 | /* If C++ then we need to __extern "C". Compiler defines __cplusplus */ 29 | #ifdef __cplusplus 30 | #define __extern extern "C" 31 | #else 32 | #define __extern extern 33 | #endif 34 | 35 | 36 | /********************************************************************** 37 | * Seek Table Types 38 | **********************************************************************/ 39 | 40 | typedef enum 41 | { 42 | seek_no_error, 43 | seek_unknown_error, 44 | seek_bad_argument, 45 | seek_malloc_failed, 46 | } seek_error_type; 47 | 48 | typedef enum 49 | { 50 | seek_false = 0, 51 | seek_true = 1 52 | } seek_boolean_type; 53 | 54 | typedef struct 55 | { 56 | int display_index; 57 | int64_t first_packet_dts; 58 | int64_t last_packet_dts; 59 | } seek_entry_type; 60 | 61 | typedef struct 62 | { 63 | seek_entry_type *array; 64 | seek_boolean_type completed; 65 | int num_frames; // total number of frames 66 | int num_entries; // ie, number of seek-points (keyframes) 67 | int allocated_size; 68 | } seek_table_type; 69 | 70 | 71 | 72 | /********************************************************************** 73 | * Seek Table Functions 74 | **********************************************************************/ 75 | 76 | 77 | __extern seek_table_type seek_init_table (int initial_size); 78 | __extern void seek_release_table (seek_table_type *table); 79 | 80 | __extern seek_table_type seek_copy_table (seek_table_type source); 81 | __extern int compare_seek_tables(seek_table_type t1, seek_table_type t2); 82 | 83 | __extern seek_error_type seek_append_table_entry (seek_table_type *table, seek_entry_type entry); 84 | 85 | __extern seek_error_type seek_get_nearest_entry (seek_table_type *table, seek_entry_type *entry, int display_index, int offset); 86 | 87 | __extern seek_error_type seek_show_table (seek_table_type table); /* human readable */ 88 | __extern seek_error_type seek_show_raw_table (FILE *file, seek_table_type table); 89 | 90 | __extern seek_table_type read_table_file(char *name); /* read raw file */ 91 | 92 | #endif 93 | 94 | /**** End of File *****************************************************/ 95 | -------------------------------------------------------------------------------- /test/build.sh: -------------------------------------------------------------------------------- 1 | LINK="../lib/libffmpeg_fas.so -lm -lz " 2 | gcc dump_frames.c -I.. $LINK -o dump_frames 3 | gcc dump_keyframes.c -I.. $LINK -o dump_keyframes 4 | gcc show_seek_table.c -I.. $LINK -o show_seek_table 5 | gcc seek_test.c -I.. $LINK -o seek_test 6 | gcc external_seek_test.c -I.. $LINK -o external_seek_test 7 | gcc generate_seek_table.c -I.. -I../ffmpeg/ ../ffmpeg/libavformat/libavformat.a ../ffmpeg/libavutil/libavutil.a ../ffmpeg/libavcodec/libavcodec.a -lm -lz ../lib/libffmpeg_fas.so -o generate_seek_table -------------------------------------------------------------------------------- /test/dump_frames.c: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * Copyright 2008. Pittsburgh Pattern Recognition, Inc. 3 | * 4 | * This file is part of the Frame Accurate Seeking extension library to 5 | * ffmpeg (ffmpeg-fas). 6 | * 7 | * ffmpeg-fas is free software; you can redistribute it and/or modify it 8 | * under the terms of the GNU Lesser General Public License as published by 9 | * the Free Software Foundation; either version 3 of the License, or (at your 10 | * option) any later version. 11 | * 12 | * The ffmpeg-fas library is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 14 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 15 | * License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public License 18 | * along with the ffmpeg-fas library. If not, see . 19 | * 20 | ******************************************************************************/ 21 | 22 | #include "ffmpeg_fas.h" 23 | #include "test_support.h" 24 | #include 25 | 26 | int main (int argc, char **argv) 27 | { 28 | char filename_buffer [255]; 29 | 30 | fas_error_type video_error; 31 | fas_context_ref_type context; 32 | fas_raw_image_type image_buffer; 33 | 34 | if (argc < 2) { 35 | fprintf (stderr, "usage: %s \n", argv[0]); 36 | return -1; 37 | } 38 | 39 | fas_initialize (FAS_FALSE, FAS_RGB24); 40 | 41 | fprintf(stderr, "%s : ",argv[1]); 42 | video_error = fas_open_video (&context, argv[1]); 43 | if (video_error != FAS_SUCCESS) 44 | fail("failed to open\n"); 45 | 46 | int counter = 0; 47 | while (fas_frame_available (context)) 48 | { 49 | 50 | if (FAS_SUCCESS != fas_get_frame (context, &image_buffer)) 51 | fail("failed on rgb image\n"); 52 | 53 | char filename[50]; 54 | sprintf(filename, "frame_%04d.ppm", counter); 55 | 56 | fprintf(stderr, "Writing %s (counter=%d frame_index=%d)\n", filename, counter, fas_get_frame_index(context)); 57 | ppm_save(&image_buffer, filename); 58 | 59 | fas_free_frame (image_buffer); 60 | 61 | video_error = fas_step_forward (context); 62 | counter++; 63 | } 64 | 65 | success(); 66 | 67 | } 68 | -------------------------------------------------------------------------------- /test/dump_keyframes.c: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * Copyright 2008. Pittsburgh Pattern Recognition, Inc. 3 | * 4 | * This file is part of the Frame Accurate Seeking extension library to 5 | * ffmpeg (ffmpeg-fas). 6 | * 7 | * ffmpeg-fas is free software; you can redistribute it and/or modify it 8 | * under the terms of the GNU Lesser General Public License as published by 9 | * the Free Software Foundation; either version 3 of the License, or (at your 10 | * option) any later version. 11 | * 12 | * The ffmpeg-fas library is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 14 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 15 | * License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public License 18 | * along with the ffmpeg-fas library. If not, see . 19 | * 20 | ******************************************************************************/ 21 | 22 | #include "ffmpeg_fas.h" 23 | #include "seek_indices.h" 24 | #include "test_support.h" 25 | #include 26 | 27 | int main (int argc, char **argv) 28 | { 29 | fas_error_type video_error; 30 | fas_context_ref_type context, seek_context; 31 | 32 | if (argc < 3) { 33 | fprintf (stderr, "usage: %s \n", argv[0]); 34 | fail("arguments\n"); 35 | } 36 | 37 | seek_table_type table = read_table_file(argv[2]); 38 | if (table.num_entries == 0) 39 | fail("bad table\n"); 40 | 41 | fas_initialize (FAS_TRUE, FAS_RGB24); 42 | 43 | video_error = fas_open_video (&context, argv[1]); 44 | if (video_error != FAS_SUCCESS) fail("fail on open\n"); 45 | 46 | video_error = fas_put_seek_table(context, table); 47 | if (video_error != FAS_SUCCESS) fail("fail on put_seek_table\n"); 48 | 49 | video_error = fas_open_video (&seek_context, argv[1]); 50 | if (video_error != FAS_SUCCESS) fail("fail on open\n"); 51 | 52 | int i; 53 | for(i=0;i. 19 | * 20 | ******************************************************************************/ 21 | 22 | /* test seek using external table */ 23 | 24 | #include "ffmpeg_fas.h" 25 | #include "seek_indices.h" 26 | #include "test_support.h" 27 | #include 28 | 29 | #define TEST_SET_SIZE 1000 30 | #define N_ITERATIONS 500 31 | 32 | int compare_frames(fas_raw_image_type img1, fas_raw_image_type img2) 33 | { 34 | // printf("(%d %d) (%d %d) (%d %d) (%d %d)\n", img1.width, img2.width, 35 | // img1.height, img2.height, 36 | // img1.bytes_per_line, img2.bytes_per_line, 37 | // img1.color_space, img2.color_space); 38 | 39 | if ((img1.width != img2.width) || 40 | (img1.height != img2.height) || 41 | (img1.bytes_per_line != img2.bytes_per_line) || 42 | (img1.color_space != img2.color_space)) 43 | return 0; 44 | 45 | int i,j; 46 | int mask = 0; 47 | 48 | for (i=0;i%d)\n", prev_index, index); 114 | 115 | fail(buffer); 116 | } 117 | 118 | fas_free_frame(test_frame); 119 | } 120 | 121 | for (i=0;i \n", argv[0]); 134 | fail("arguments\n"); 135 | } 136 | 137 | fprintf(stderr, "%s : ", argv[1]); 138 | 139 | seek_table_type table = read_table_file(argv[2]); 140 | if (table.num_entries == 0) 141 | fail("bad table\n"); 142 | 143 | fas_initialize (FAS_FALSE, FAS_RGB24); 144 | 145 | video_error = fas_open_video (&context, argv[1]); 146 | if (video_error != FAS_SUCCESS) fail("fail on open\n"); 147 | 148 | video_error = fas_put_seek_table(context, table); 149 | if (video_error != FAS_SUCCESS) fail("fail on put_seek_table\n"); 150 | 151 | if (fas_get_frame_count(context) < 0) 152 | fail("n_frames = -1\n"); 153 | 154 | if (fas_get_frame_count(context) < TEST_SET_SIZE) 155 | do_random_test(context, 0, fas_get_frame_count(context) - 1, N_ITERATIONS); 156 | else if (fas_get_frame_count(context) < TEST_SET_SIZE * 2) 157 | { 158 | do_random_test(context, 0, fas_get_frame_count(context) / 2 - 1, N_ITERATIONS / 2); 159 | do_random_test(context, fas_get_frame_count(context) / 2 + 1, fas_get_frame_count(context) - 1 , N_ITERATIONS / 2); 160 | } 161 | else 162 | { 163 | do_random_test(context, 0, TEST_SET_SIZE, N_ITERATIONS / 2); 164 | do_random_test(context, fas_get_frame_count(context) - TEST_SET_SIZE, fas_get_frame_count(context) - 1 , N_ITERATIONS / 2); 165 | } 166 | 167 | seek_release_table(&table); 168 | fas_close_video(context); 169 | 170 | success(); 171 | } 172 | 173 | -------------------------------------------------------------------------------- /test/generate_seek_table.c: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * Copyright 2008. Pittsburgh Pattern Recognition, Inc. 3 | * 4 | * This file is part of the Frame Accurate Seeking extension library to 5 | * ffmpeg (ffmpeg-fas). 6 | * 7 | * ffmpeg-fas is free software; you can redistribute it and/or modify it 8 | * under the terms of the GNU Lesser General Public License as published by 9 | * the Free Software Foundation; either version 3 of the License, or (at your 10 | * option) any later version. 11 | * 12 | * The ffmpeg-fas library is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 14 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 15 | * License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public License 18 | * along with the ffmpeg-fas library. If not, see . 19 | * 20 | ******************************************************************************/ 21 | 22 | #include "libavcodec/avcodec.h" 23 | #include "libavformat/avformat.h" 24 | #include 25 | #include 26 | #include "seek_indices.h" 27 | 28 | /* This executable is used for creating experimental seek tables. 29 | The show_seek_table executable will show the seek-table as ffmpeg_fas 30 | currently creates them. 31 | */ 32 | 33 | int main (int argc, char **argv) 34 | { 35 | av_log_level = AV_LOG_QUIET; 36 | 37 | if (argc < 2) { 38 | fprintf (stderr, "usage: %s \n", argv[0]); 39 | return -1; 40 | } 41 | 42 | av_register_all(); 43 | 44 | AVFormatContext *pFormatCtx; 45 | if (av_open_input_file(&pFormatCtx, argv[1], NULL, 0, NULL) !=0) 46 | return -1; 47 | 48 | if (av_find_stream_info(pFormatCtx)<0) 49 | return -1; 50 | 51 | unsigned int stream_id = -1; 52 | unsigned int i; 53 | 54 | for (i = 0; i < pFormatCtx->nb_streams; i++) 55 | if (pFormatCtx->streams[i]->codec->codec_type == CODEC_TYPE_VIDEO) 56 | { 57 | stream_id = i; 58 | break; 59 | } 60 | 61 | if (stream_id == -1) 62 | return -1; 63 | 64 | AVCodecContext *pCodecCtx = pFormatCtx->streams[stream_id]->codec; 65 | AVCodec *pCodec; 66 | pCodec = avcodec_find_decoder(pCodecCtx->codec_id); 67 | if (pCodec==NULL) 68 | return -1; 69 | 70 | if (avcodec_open(pCodecCtx, pCodec)<0) 71 | return -1; 72 | 73 | 74 | // printf("\n%s \n",argv[1]); 75 | 76 | AVPacket Packet; 77 | int count = 0; 78 | int key_packets = 0; 79 | int non_key_packets = 0; 80 | 81 | int frame_count = 0; 82 | int key_frames = 0; 83 | int non_key_frames = 0; 84 | 85 | AVFrame *pFrame; 86 | pFrame=avcodec_alloc_frame(); 87 | int frameFinished; 88 | 89 | seek_table_type table; 90 | table = seek_init_table (16); 91 | seek_entry_type entry; 92 | 93 | int64_t key_packet_dts; 94 | int64_t prev_packet_dts = AV_NOPTS_VALUE; 95 | int64_t first_packet_dts; /* ensure first keyframe gets first packet */ 96 | 97 | int is_first_packet = 1; 98 | int frames_have_label = 1; 99 | 100 | // const char *format_name = pFormatCtx->iformat->name; 101 | // const char *codec_name = pFormatCtx->streams[stream_id]->codec->codec->name; 102 | 103 | 104 | /* these avi formats do not have labeled keyframes (the packets are labeled only and the packets and keyframe align 1-to-1 */ 105 | /* DISABLING THIS TYPE OF GENERATION (these videos will be unseekable) */ 106 | // fprintf(stderr, "format: (%s) codec: (%s)\n", format_name, codec_name); 107 | /* 108 | * if (!strcmp(format_name, "avi")) 109 | * if (!strcmp(codec_name, "aasc") || 110 | * !strcmp(codec_name, "camtasia") || 111 | * !strcmp(codec_name, "cinepak") || 112 | * !strcmp(codec_name, "cyuv") || 113 | * !strcmp(codec_name, "huffyuv") || 114 | * !strcmp(codec_name, "indeo2") || 115 | * !strcmp(codec_name, "indeo3") || 116 | * !strcmp(codec_name, "msrle") || 117 | * !strcmp(codec_name, "msvideo1") || 118 | * !strcmp(codec_name, "mszh") || 119 | * !strcmp(codec_name, "qpeg") || 120 | * !strcmp(codec_name, "truemotion1") || 121 | * !strcmp(codec_name, "ultimotion") || 122 | * !strcmp(codec_name, "vp3") || 123 | * !strcmp(codec_name, "zlib")) 124 | * frames_have_label = 0; 125 | */ 126 | 127 | while (av_read_frame(pFormatCtx, &Packet) >= 0) 128 | { 129 | if (Packet.stream_index == stream_id) 130 | { 131 | // fprintf(stderr, "Packet: (P%d: %lld %lld %d)\n", count, Packet.pts, Packet.dts, Packet.flags); 132 | if ((Packet.flags & PKT_FLAG_KEY) || is_first_packet ) 133 | { 134 | /* when keyframes overlap in the stream, that means multiple packets labeled 'keyframe' will arrive before 135 | the keyframe itself. this results in wrong assignments all around, but only the first one needs to be right. 136 | for all the rest, the seek-code will rewind to the previous keyframe to get them right. 137 | */ 138 | if (is_first_packet) 139 | { 140 | first_packet_dts = Packet.dts; 141 | is_first_packet = 0; 142 | } 143 | 144 | // fprintf(stderr, "Packet: (P%d: %lld %lld)\n", count, Packet.pts, Packet.dts); 145 | 146 | /* first keyframe gets own dts, others get previous packet's dts.. this is workaround for some mpegs */ 147 | /* sometimes you need the previous packet from the supposed keyframe packet to get a frame back that is */ 148 | /* actually a keyframe */ 149 | 150 | if (prev_packet_dts == AV_NOPTS_VALUE) 151 | key_packet_dts = Packet.dts; 152 | else 153 | key_packet_dts = prev_packet_dts; 154 | 155 | if (Packet.flags & PKT_FLAG_KEY) 156 | key_packets++; 157 | else 158 | non_key_packets++; 159 | } 160 | else 161 | non_key_packets++; 162 | 163 | 164 | avcodec_decode_video(pCodecCtx, pFrame, &frameFinished, Packet.data, Packet.size); 165 | 166 | if (frameFinished) 167 | { 168 | 169 | // fprintf(stderr, "Frame : (P%d F%d: %lld %lld L:%d)\n", count, frame_count, Packet.pts, Packet.dts, pFrame->key_frame); 170 | if ((pFrame->key_frame && frames_have_label) || ((Packet.flags & PKT_FLAG_KEY) && !frames_have_label)) 171 | { 172 | key_frames++; 173 | 174 | entry.display_index = frame_count; 175 | entry.first_packet_dts = key_packet_dts; 176 | entry.last_packet_dts = Packet.dts; 177 | 178 | /* ensure first keyframe gets first packet dts */ 179 | if (frame_count == 0) 180 | entry.first_packet_dts = first_packet_dts; 181 | 182 | seek_append_table_entry(&table, entry); 183 | 184 | // fprintf(stderr, "Frame : (P%d F%d: %lld %lld)\n", count, frame_count, Packet.pts, Packet.dts); 185 | } 186 | else 187 | non_key_frames++; 188 | frame_count++; 189 | } 190 | 191 | count++; 192 | prev_packet_dts = Packet.dts; 193 | } 194 | 195 | av_free_packet(&Packet); 196 | } 197 | 198 | // printf("\n"); 199 | 200 | fprintf (stderr, "Packets: key: %d nonkey: %d total: %d\n", key_packets, non_key_packets, count); 201 | fprintf (stderr, "Frames : key: %d nonkey: %d total: %d\n", key_frames, non_key_frames, frame_count); 202 | 203 | table.completed = seek_true; 204 | table.num_frames = frame_count; 205 | 206 | seek_show_raw_table(stdout, table); 207 | 208 | return 1; 209 | } 210 | -------------------------------------------------------------------------------- /test/movie_info.c: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * Copyright 2008. Pittsburgh Pattern Recognition, Inc. 3 | * 4 | * This file is part of the Frame Accurate Seeking extension library to 5 | * ffmpeg (ffmpeg-fas). 6 | * 7 | * ffmpeg-fas is free software; you can redistribute it and/or modify it 8 | * under the terms of the GNU Lesser General Public License as published by 9 | * the Free Software Foundation; either version 3 of the License, or (at your 10 | * option) any later version. 11 | * 12 | * The ffmpeg-fas library is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 14 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 15 | * License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public License 18 | * along with the ffmpeg-fas library. If not, see . 19 | * 20 | ******************************************************************************/ 21 | 22 | #include 23 | #include 24 | 25 | #include 26 | 27 | int main(int argc, char *argv[]) { 28 | AVFormatContext *pFormatCtx; 29 | int i, videoStream; 30 | AVCodecContext *pCodecCtx; 31 | AVCodec *pCodec; 32 | AVFrame *pFrame; 33 | AVFrame *pFrameRGB; 34 | AVPacket packet; 35 | int frameFinished; 36 | int numBytes; 37 | uint8_t *buffer; 38 | 39 | if(argc < 2) { 40 | printf("Please provide a movie file\n"); 41 | return -1; 42 | } 43 | // Register all formats and codecs 44 | av_register_all(); 45 | 46 | // Open video file 47 | if(av_open_input_file(&pFormatCtx, argv[1], NULL, 0, NULL)!=0) 48 | return -1; // Couldn't open file 49 | 50 | // Retrieve stream information 51 | if(av_find_stream_info(pFormatCtx)<0) 52 | return -1; // Couldn't find stream information 53 | 54 | // Dump information about file onto standard error 55 | dump_format(pFormatCtx, 0, argv[1], 0); 56 | 57 | // Find the first video stream 58 | videoStream=-1; 59 | for(i=0; inb_streams; i++) 60 | if(pFormatCtx->streams[i]->codec->codec_type==CODEC_TYPE_VIDEO) { 61 | videoStream=i; 62 | break; 63 | } 64 | if(videoStream==-1) 65 | return -1; // Didn't find a video stream 66 | 67 | // Get a pointer to the codec context for the video stream 68 | pCodecCtx=pFormatCtx->streams[videoStream]->codec; 69 | 70 | // Find the decoder for the video stream 71 | pCodec=avcodec_find_decoder(pCodecCtx->codec_id); 72 | if(pCodec==NULL) { 73 | fprintf(stderr, "Unsupported codec!\n"); 74 | return -1; // Codec not found 75 | } 76 | // Open codec 77 | if(avcodec_open(pCodecCtx, pCodec)<0) 78 | return -1; // Could not open codec 79 | 80 | return 0; 81 | } 82 | -------------------------------------------------------------------------------- /test/run_test.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | import sys 4 | import os 5 | 6 | def readFilelist(filename): 7 | try: 8 | f = open(filename, 'r') 9 | except: 10 | return [] 11 | return [ele[:-1] for ele in f.readlines()] 12 | 13 | def create_filter_func(cmd, log_file): 14 | if log_file == "": 15 | return lambda filename : 0 == os.system(cmd + " " + filename) 16 | else: 17 | return lambda filename : 0 == os.system(cmd + " " + filename + " 2>> " + log_file) 18 | 19 | def write_filelist(files, filename): 20 | f = open(filename, 'w') 21 | for arg in files: 22 | f.write(arg + '\n') 23 | f.close() 24 | 25 | if __name__ == "__main__": 26 | if len(sys.argv) < 3 or len(sys.argv) > 4: 27 | print "Usage: " + sys.argv[0] + " " 28 | raise SystemExit 29 | 30 | 31 | if not os.path.isfile(sys.argv[1]): 32 | print sys.argv[1] + " not found" 33 | raise SystemExit 34 | 35 | cmd = sys.argv[1] 36 | base_name = cmd.split('/')[-1] 37 | 38 | success_file = base_name + ".pass" 39 | fail_file = base_name + ".fail" 40 | 41 | if len(sys.argv) == 4: 42 | log_file = sys.argv[3] 43 | if os.path.isfile(log_file): 44 | os.system("rm " + log_file) 45 | else: 46 | log_file = "" 47 | 48 | files = readFilelist(sys.argv[2]) 49 | 50 | filterfunc = create_filter_func(cmd, log_file) 51 | successful = filter(filterfunc, files) 52 | failed = list(set(files) - set(successful)) 53 | 54 | write_filelist(failed, fail_file) 55 | write_filelist(successful, success_file) 56 | 57 | -------------------------------------------------------------------------------- /test/seek_test.c: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * Copyright 2008. Pittsburgh Pattern Recognition, Inc. 3 | * 4 | * This file is part of the Frame Accurate Seeking extension library to 5 | * ffmpeg (ffmpeg-fas). 6 | * 7 | * ffmpeg-fas is free software; you can redistribute it and/or modify it 8 | * under the terms of the GNU Lesser General Public License as published by 9 | * the Free Software Foundation; either version 3 of the License, or (at your 10 | * option) any later version. 11 | * 12 | * The ffmpeg-fas library is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 14 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 15 | * License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public License 18 | * along with the ffmpeg-fas library. If not, see . 19 | * 20 | ******************************************************************************/ 21 | 22 | #include "ffmpeg_fas.h" 23 | #include "seek_indices.h" 24 | #include "test_support.h" 25 | #include 26 | 27 | #define TEST_SET_SIZE 1000 28 | #define N_ITERATIONS 500 29 | 30 | int compare_frames(fas_raw_image_type img1, fas_raw_image_type img2) 31 | { 32 | // printf("(%d %d) (%d %d) (%d %d) (%d %d)\n", img1.width, img2.width, 33 | // img1.height, img2.height, 34 | // img1.bytes_per_line, img2.bytes_per_line, 35 | // img1.color_space, img2.color_space); 36 | 37 | if ((img1.width != img2.width) || 38 | (img1.height != img2.height) || 39 | (img1.bytes_per_line != img2.bytes_per_line) || 40 | (img1.color_space != img2.color_space)) 41 | return 0; 42 | 43 | int i,j; 44 | int mask = 0; 45 | 46 | for (i=0;i%d)\n", prev_index, index); 112 | 113 | fail(buffer); 114 | } 115 | 116 | fas_free_frame(test_frame); 117 | } 118 | 119 | for (i=0;i\n", argv[0]); 132 | fail("arguments\n"); 133 | } 134 | 135 | fprintf(stderr, "%s : ", argv[1]); 136 | 137 | fas_initialize (FAS_FALSE, FAS_RGB24); 138 | 139 | video_error = fas_open_video (&context, argv[1]); 140 | if (video_error != FAS_SUCCESS) fail("fail on open\n"); 141 | 142 | if (fas_get_frame_count(context) < 0) 143 | fail("failed on counting frames (completing seek table... bad table?)\n"); 144 | 145 | if (fas_get_frame_count(context) < TEST_SET_SIZE) 146 | do_random_test(context, 0, fas_get_frame_count(context) - 1, N_ITERATIONS); 147 | else if (fas_get_frame_count(context) < TEST_SET_SIZE * 2) 148 | { 149 | do_random_test(context, 0, fas_get_frame_count(context) / 2 - 1, N_ITERATIONS / 2); 150 | do_random_test(context, fas_get_frame_count(context) / 2 + 1, fas_get_frame_count(context) - 1 , N_ITERATIONS / 2); 151 | } 152 | else 153 | { 154 | do_random_test(context, 0, TEST_SET_SIZE, N_ITERATIONS / 2); 155 | do_random_test(context, fas_get_frame_count(context) - TEST_SET_SIZE, fas_get_frame_count(context) - 1 , N_ITERATIONS / 2); 156 | } 157 | 158 | fas_close_video(context); 159 | 160 | success(); 161 | } 162 | 163 | -------------------------------------------------------------------------------- /test/show_seek_table.c: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * Copyright 2008. Pittsburgh Pattern Recognition, Inc. 3 | * 4 | * This file is part of the Frame Accurate Seeking extension library to 5 | * ffmpeg (ffmpeg-fas). 6 | * 7 | * ffmpeg-fas is free software; you can redistribute it and/or modify it 8 | * under the terms of the GNU Lesser General Public License as published by 9 | * the Free Software Foundation; either version 3 of the License, or (at your 10 | * option) any later version. 11 | * 12 | * The ffmpeg-fas library is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 14 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 15 | * License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public License 18 | * along with the ffmpeg-fas library. If not, see . 19 | * 20 | ******************************************************************************/ 21 | 22 | #include "seek_indices.h" 23 | #include "ffmpeg_fas.h" 24 | #include 25 | 26 | int main (int argc, char **argv) 27 | { 28 | fas_error_type video_error; 29 | fas_context_ref_type context; 30 | fas_raw_image_type image_buffer; 31 | 32 | if (argc < 2) { 33 | fprintf (stderr, "usage: %s \n", argv[0]); 34 | return -1; 35 | } 36 | 37 | fas_initialize (FAS_FALSE, FAS_RGB24); 38 | 39 | video_error = fas_open_video (&context, argv[1]); 40 | if (video_error != FAS_SUCCESS) 41 | return -1; 42 | 43 | while (fas_frame_available (context)) 44 | { 45 | if (FAS_SUCCESS != fas_get_frame (context, &image_buffer)) 46 | return -1; 47 | fas_free_frame (image_buffer); 48 | 49 | video_error = fas_step_forward (context); 50 | } 51 | 52 | seek_table_type table; 53 | table = fas_get_seek_table(context); 54 | 55 | seek_show_raw_table(stdout, table); 56 | 57 | return 1; 58 | } 59 | 60 | -------------------------------------------------------------------------------- /test/test_support.h: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * Copyright 2008. Pittsburgh Pattern Recognition, Inc. 3 | * 4 | * This file is part of the Frame Accurate Seeking extension library to 5 | * ffmpeg (ffmpeg-fas). 6 | * 7 | * ffmpeg-fas is free software; you can redistribute it and/or modify it 8 | * under the terms of the GNU Lesser General Public License as published by 9 | * the Free Software Foundation; either version 3 of the License, or (at your 10 | * option) any later version. 11 | * 12 | * The ffmpeg-fas library is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 14 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 15 | * License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public License 18 | * along with the ffmpeg-fas library. If not, see . 19 | * 20 | ******************************************************************************/ 21 | 22 | #ifndef FAS_TEST_SUPPORT 23 | #define FAS_TEST_SUPPORT 24 | 25 | #include 26 | #include 27 | 28 | #define fail(x) { fprintf(stderr, "fail : "); fprintf(stderr, x); exit(EXIT_FAILURE); } 29 | #define success() { fprintf(stderr, "success\n"); exit(EXIT_SUCCESS); } 30 | 31 | /* 32 | * static void pgm_save(ppt_raw_image_type *image, char *filename) 33 | * { 34 | * FILE *f; 35 | * int i; 36 | * 37 | * f=fopen(filename,"w"); 38 | * fprintf(f,"P5\n%d\n%d\n%d\n", image->width, image->height, 255); 39 | * 40 | * for(i=0; iheight; i++) { 41 | * fwrite(image->data + i * image->bytes_per_line, 1, image->width, f); 42 | * } 43 | * 44 | * fclose(f); 45 | * } 46 | */ 47 | 48 | static void ppm_save(fas_raw_image_type *image, char *filename) 49 | { 50 | FILE *f; 51 | int i; 52 | 53 | if (image->color_space != FAS_RGB24) { 54 | return; 55 | } 56 | 57 | f=fopen(filename,"wb"); 58 | fprintf(f,"P6\n%d %d\n%d\n", image->width, image->height, 255); 59 | 60 | for(i=0; iheight; i++) { 61 | fwrite(image->data + i * image->bytes_per_line, 1, image->width * 3, f); 62 | } 63 | 64 | fclose(f); 65 | } 66 | 67 | #endif 68 | --------------------------------------------------------------------------------