├── .gitignore ├── .gitlab-ci.yml ├── AUTHORS ├── COPYING ├── ChangeLog ├── NEWS ├── README.md ├── RELEASE ├── docs ├── gst_plugins_cache.json ├── index.md ├── meson.build └── sitemap.txt ├── ext └── libav │ ├── gstav.c │ ├── gstav.h │ ├── gstavauddec.c │ ├── gstavauddec.h │ ├── gstavaudenc.c │ ├── gstavaudenc.h │ ├── gstavcfg.c │ ├── gstavcfg.h │ ├── gstavcodecmap.c │ ├── gstavcodecmap.h │ ├── gstavdeinterlace.c │ ├── gstavdemux.c │ ├── gstavmux.c │ ├── gstavprotocol.c │ ├── gstavprotocol.h │ ├── gstavutils.c │ ├── gstavutils.h │ ├── gstavviddec.c │ ├── gstavviddec.h │ ├── gstavvidenc.c │ ├── gstavvidenc.h │ └── meson.build ├── gst-libav.doap ├── hooks └── pre-commit.hook ├── meson.build ├── meson_options.txt ├── scripts └── extract-release-date-from-doap-file.py └── tests ├── check ├── elements │ ├── avaudenc.c │ ├── avdec_adpcm.c │ ├── avdemux_ape.c │ └── avvidenc.c ├── generic │ ├── libavcodec-locking.c │ └── plugin-test.c ├── gst-libav.supp └── meson.build ├── files ├── 586957.ape └── 591809.wav └── meson.build /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | 3 | Build 4 | *.user 5 | *.suo 6 | *.ipch 7 | *.sdf 8 | *.opensdf 9 | *.DS_Store 10 | -------------------------------------------------------------------------------- /.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | include: "https://gitlab.freedesktop.org/gstreamer/gst-ci/raw/master/gitlab/ci_template.yml" 2 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | Ronald Bultje 2 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 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 St, 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 St, 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 | -------------------------------------------------------------------------------- /NEWS: -------------------------------------------------------------------------------- 1 | GStreamer 1.20 Release Notes 2 | 3 | GStreamer 1.20 has not been released yet. It is scheduled for release 4 | around October/November 2021. 5 | 6 | 1.19.x is the unstable development version that is being developed in 7 | the git main branch and which will eventually result in 1.20, and 1.19.2 8 | is the current development release in that series 9 | 10 | It is expected that feature freeze will be in early October 2021, 11 | followed by one or two 1.19.9x pre-releases and the new 1.20 stable 12 | release around October/November 2021. 13 | 14 | 1.20 will be backwards-compatible to the stable 1.18, 1.16, 1.14, 1.12, 15 | 1.10, 1.8, 1.6,, 1.4, 1.2 and 1.0 release series. 16 | 17 | See https://gstreamer.freedesktop.org/releases/1.20/ for the latest 18 | version of this document. 19 | 20 | Last updated: Wednesday 22 September 2021, 18:00 UTC (log) 21 | 22 | Introduction 23 | 24 | The GStreamer team is proud to announce a new major feature release in 25 | the stable 1.x API series of your favourite cross-platform multimedia 26 | framework! 27 | 28 | As always, this release is again packed with many new features, bug 29 | fixes and other improvements. 30 | 31 | Highlights 32 | 33 | - this section will be completed in due course 34 | 35 | Major new features and changes 36 | 37 | Noteworthy new features and API 38 | 39 | - this section will be filled in in due course 40 | 41 | New elements 42 | 43 | - this section will be filled in in due course 44 | 45 | New element features and additions 46 | 47 | - this section will be filled in in due course 48 | 49 | Plugin and library moves 50 | 51 | - this section will be filled in in due course 52 | 53 | - There were no plugin moves or library moves in this cycle. 54 | 55 | Plugin removals 56 | 57 | The following elements or plugins have been removed: 58 | 59 | - this section will be filled in in due course 60 | 61 | Miscellaneous API additions 62 | 63 | - this section will be filled in in due course 64 | 65 | Miscellaneous performance, latency and memory optimisations 66 | 67 | - this section will be filled in in due course 68 | 69 | Miscellaneous other changes and enhancements 70 | 71 | - this section will be filled in in due course 72 | 73 | Tracing framework and debugging improvements 74 | 75 | - this section will be filled in in due course 76 | 77 | Tools 78 | 79 | - this section will be filled in in due course 80 | 81 | GStreamer RTSP server 82 | 83 | - this section will be filled in in due course 84 | 85 | GStreamer VAAPI 86 | 87 | - this section will be filled in in due course 88 | 89 | GStreamer OMX 90 | 91 | - this section will be filled in in due course 92 | 93 | GStreamer Editing Services and NLE 94 | 95 | - this section will be filled in in due course 96 | 97 | GStreamer validate 98 | 99 | - this section will be filled in in due course 100 | 101 | GStreamer Python Bindings 102 | 103 | - this section will be filled in in due course 104 | 105 | GStreamer C# Bindings 106 | 107 | - this section will be filled in in due course 108 | 109 | GStreamer Rust Bindings and Rust Plugins 110 | 111 | The GStreamer Rust bindings are released separately with a different 112 | release cadence that’s tied to gtk-rs, but the latest release has 113 | already been updated for the upcoming new GStreamer 1.20 API. 114 | 115 | gst-plugins-rs, the module containing GStreamer plugins written in Rust, 116 | has also seen lots of activity with many new elements and plugins. 117 | 118 | What follows is a list of elements and plugins available in 119 | gst-plugins-rs, so people don’t miss out on all those potentially useful 120 | elements that have no C equivalent. 121 | 122 | - FIXME: add new elements 123 | 124 | Rust audio plugins 125 | 126 | - audiornnoise: New element for audio denoising which implements the 127 | noise removal algorithm of the Xiph RNNoise library, in Rust 128 | - rsaudioecho: Port of the audioecho element from gst-plugins-good 129 | rsaudioloudnorm: Live audio loudness normalization element based on 130 | the FFmpeg af_loudnorm filter 131 | - claxondec: FLAC lossless audio codec decoder element based on the 132 | pure-Rust claxon implementation 133 | - csoundfilter: Audio filter that can use any filter defined via the 134 | Csound audio programming language 135 | - lewtondec: Vorbis audio decoder element based on the pure-Rust 136 | lewton implementation 137 | 138 | Rust video plugins 139 | 140 | - cdgdec/cdgparse: Decoder and parser for the CD+G video codec based 141 | on a pure-Rust CD+G implementation, used for example by karaoke CDs 142 | - cea608overlay: CEA-608 Closed Captions overlay element 143 | - cea608tott: CEA-608 Closed Captions to timed-text (e.g. VTT or SRT 144 | subtitles) converter 145 | - tttocea608: CEA-608 Closed Captions from timed-text converter 146 | - mccenc/mccparse: MacCaption Closed Caption format encoder and parser 147 | - sccenc/sccparse: Scenarist Closed Caption format encoder and parser 148 | - dav1dec: AV1 video decoder based on the dav1d decoder implementation 149 | by the VLC project 150 | - rav1enc: AV1 video encoder based on the fast and pure-Rust rav1e 151 | encoder implementation 152 | - rsflvdemux: Alternative to the flvdemux FLV demuxer element from 153 | gst-plugins-good, not feature-equivalent yet 154 | - rsgifenc/rspngenc: GIF/PNG encoder elements based on the pure-Rust 155 | implementations by the image-rs project 156 | 157 | Rust text plugins 158 | 159 | - textwrap: Element for line-wrapping timed text (e.g. subtitles) for 160 | better screen-fitting, including hyphenation support for some 161 | languages 162 | 163 | Rust network plugins 164 | 165 | - reqwesthttpsrc: HTTP(S) source element based on the Rust 166 | reqwest/hyper HTTP implementations and almost feature-equivalent 167 | with the main GStreamer HTTP source souphttpsrc 168 | - s3src/s3sink: Source/sink element for the Amazon S3 cloud storage 169 | - awstranscriber: Live audio to timed text transcription element using 170 | the Amazon AWS Transcribe API 171 | 172 | Generic Rust plugins 173 | 174 | - sodiumencrypter/sodiumdecrypter: Encryption/decryption element based 175 | on libsodium/NaCl 176 | - togglerecord: Recording element that allows to pause/resume 177 | recordings easily and considers keyframe boundaries 178 | - fallbackswitch/fallbacksrc: Elements for handling potentially 179 | failing (network) sources, restarting them on errors/timeout and 180 | showing a fallback stream instead 181 | - threadshare: Set of elements that provide alternatives for various 182 | existing GStreamer elements but allow to share the streaming threads 183 | between each other to reduce the number of threads 184 | - rsfilesrc/rsfilesink: File source/sink elements as replacements for 185 | the existing filesrc/filesink elements 186 | 187 | Build and Dependencies 188 | 189 | - this section will be filled in in due course 190 | 191 | gst-build 192 | 193 | - this section will be filled in in due course 194 | 195 | Cerbero 196 | 197 | Cerbero is a meta build system used to build GStreamer plus dependencies 198 | on platforms where dependencies are not readily available, such as 199 | Windows, Android, iOS and macOS. 200 | 201 | General improvements 202 | 203 | - this section will be filled in in due course 204 | 205 | macOS / iOS 206 | 207 | - this section will be filled in in due course 208 | 209 | Windows 210 | 211 | - this section will be filled in in due course 212 | 213 | Windows MSI installer 214 | 215 | - this section will be filled in in due course 216 | 217 | Linux 218 | 219 | - this section will be filled in in due course 220 | 221 | Android 222 | 223 | - this section will be filled in in due course 224 | 225 | Platform-specific changes and improvements 226 | 227 | Android 228 | 229 | - this section will be filled in in due course 230 | 231 | macOS and iOS 232 | 233 | - this section will be filled in in due course 234 | 235 | Windows 236 | 237 | - this section will be filled in in due course 238 | 239 | Linux 240 | 241 | - this section will be filled in in due course 242 | 243 | Documentation improvements 244 | 245 | - this section will be filled in in due course 246 | 247 | Possibly Breaking Changes 248 | 249 | - this section will be filled in in due course 250 | - MPEG-TS SCTE-35 API changes (FIXME: flesh out) 251 | - gst_parse_launch() and friends now error out on non-existing 252 | properties on top-level bins where they would silently fail and 253 | ignore those before. 254 | 255 | Known Issues 256 | 257 | - this section will be filled in in due course 258 | 259 | - There are a couple of known WebRTC-related regressions/blockers: 260 | 261 | - webrtc: DTLS setup with Chrome is broken 262 | - webrtcbin: First keyframe is usually lost 263 | 264 | Contributors 265 | 266 | - this section will be filled in in due course 267 | 268 | … and many others who have contributed bug reports, translations, sent 269 | suggestions or helped testing. 270 | 271 | Stable 1.20 branch 272 | 273 | After the 1.20.0 release there will be several 1.20.x bug-fix releases 274 | which will contain bug fixes which have been deemed suitable for a 275 | stable branch, but no new features or intrusive changes will be added to 276 | a bug-fix release usually. The 1.20.x bug-fix releases will be made from 277 | the git 1.20 branch, which will be a stable branch. 278 | 279 | 1.20.0 280 | 281 | 1.20.0 is scheduled to be released around October/November 2021. 282 | 283 | Schedule for 1.22 284 | 285 | Our next major feature release will be 1.22, and 1.21 will be the 286 | unstable development version leading up to the stable 1.22 release. The 287 | development of 1.21/1.22 will happen in the git main branch. 288 | 289 | The plan for the 1.22 development cycle is yet to be confirmed. 290 | 291 | 1.22 will be backwards-compatible to the stable 1.20, 1.18, 1.16, 1.14, 292 | 1.12, 1.10, 1.8, 1.6, 1.4, 1.2 and 1.0 release series. 293 | 294 | ------------------------------------------------------------------------ 295 | 296 | These release notes have been prepared by Tim-Philipp Müller with 297 | contributions from … 298 | 299 | License: CC BY-SA 4.0 300 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # gst-libav 2 | 3 | This module contains a GStreamer plugin for using the encoders, decoders, 4 | muxers, and demuxers provided by FFmpeg. It is called gst-libav for historical 5 | reasons. 6 | 7 | # Plugin Dependencies and Licenses 8 | 9 | GStreamer is developed under the terms of the LGPL-2.1 (see COPYING file for 10 | details), and that includes the code in this repository. 11 | 12 | However, this repository depends on FFmpeg, which can be built in the following 13 | modes using various `./configure` switches: LGPL-2.1, LGPL-3, GPL, or non-free. 14 | 15 | This can mean, for example, that if you are distributing an application which 16 | has a non-GPL compatible license (like a closed-source application) with 17 | GStreamer, you have to make sure not to build FFmpeg with GPL code enabled. 18 | 19 | Overall, when using plugins that link to GPL libraries, GStreamer is for all 20 | practical reasons under the GPL itself. 21 | 22 | The above recommendations are not legal advice, and you are responsible for 23 | ensuring that you meet your licensing obligations. 24 | -------------------------------------------------------------------------------- /RELEASE: -------------------------------------------------------------------------------- 1 | This is GStreamer gst-libav 1.19.2. 2 | 3 | GStreamer 1.19 is the development branch leading up to the next major 4 | stable version which will be 1.20. 5 | 6 | The 1.19 development series adds new features on top of the 1.18 series and is 7 | part of the API and ABI-stable 1.x release series of the GStreamer multimedia 8 | framework. 9 | 10 | Full release notes will one day be found at: 11 | 12 | https://gstreamer.freedesktop.org/releases/1.20/ 13 | 14 | Binaries for Android, iOS, Mac OS X and Windows will usually be provided 15 | shortly after the release. 16 | 17 | This module will not be very useful by itself and should be used in conjunction 18 | with other GStreamer modules for a complete multimedia experience. 19 | 20 | - gstreamer: provides the core GStreamer libraries and some generic plugins 21 | 22 | - gst-plugins-base: a basic set of well-supported plugins and additional 23 | media-specific GStreamer helper libraries for audio, 24 | video, rtsp, rtp, tags, OpenGL, etc. 25 | 26 | - gst-plugins-good: a set of well-supported plugins under our preferred 27 | license 28 | 29 | - gst-plugins-ugly: a set of well-supported plugins which might pose 30 | problems for distributors 31 | 32 | - gst-plugins-bad: a set of plugins of varying quality that have not made 33 | their way into one of core/base/good/ugly yet, for one 34 | reason or another. Many of these are are production quality 35 | elements, but may still be missing documentation or unit 36 | tests; others haven't passed the rigorous quality testing 37 | we expect yet. 38 | 39 | - gst-libav: a set of codecs plugins based on the ffmpeg library. This is 40 | where you can find audio and video decoders and encoders 41 | for a wide variety of formats including H.264, AAC, etc. 42 | 43 | - gstreamer-vaapi: hardware-accelerated video decoding and encoding using 44 | VA-API on Linux. Primarily for Intel graphics hardware. 45 | 46 | - gst-omx: hardware-accelerated video decoding and encoding, primarily for 47 | embedded Linux systems that provide an OpenMax 48 | implementation layer such as the Raspberry Pi. 49 | 50 | - gst-rtsp-server: library to serve files or streaming pipelines via RTSP 51 | 52 | - gst-editing-services: library an plugins for non-linear editing 53 | 54 | ==== Download ==== 55 | 56 | You can find source releases of gstreamer in the download 57 | directory: https://gstreamer.freedesktop.org/src/gstreamer/ 58 | 59 | The git repository and details how to clone it can be found at 60 | https://gitlab.freedesktop.org/gstreamer/ 61 | 62 | ==== Homepage ==== 63 | 64 | The project's website is https://gstreamer.freedesktop.org/ 65 | 66 | ==== Support and Bugs ==== 67 | 68 | We have recently moved from GNOME Bugzilla to GitLab on freedesktop.org 69 | for bug reports and feature requests: 70 | 71 | https://gitlab.freedesktop.org/gstreamer 72 | 73 | Please submit patches via GitLab as well, in form of Merge Requests. See 74 | 75 | https://gstreamer.freedesktop.org/documentation/contribute/ 76 | 77 | for more details. 78 | 79 | For help and support, please subscribe to and send questions to the 80 | gstreamer-devel mailing list (see below for details). 81 | 82 | There is also a #gstreamer IRC channel on the Freenode IRC network. 83 | 84 | ==== Developers ==== 85 | 86 | GStreamer source code repositories can be found on GitLab on freedesktop.org: 87 | 88 | https://gitlab.freedesktop.org/gstreamer 89 | 90 | and can also be cloned from there and this is also where you can submit 91 | Merge Requests or file issues for bugs or feature requests. 92 | 93 | Interested developers of the core library, plugins, and applications should 94 | subscribe to the gstreamer-devel list: 95 | 96 | https://lists.freedesktop.org/mailman/listinfo/gstreamer-devel 97 | -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | short-description: GStreamer plugins from gst-ffmpeg 3 | ... 4 | 5 | # FFMPEG plugin 6 | -------------------------------------------------------------------------------- /docs/meson.build: -------------------------------------------------------------------------------- 1 | build_hotdoc = false 2 | 3 | if meson.is_cross_build() 4 | if get_option('doc').enabled() 5 | error('Documentation enabled but building the doc while cross building is not supported yet.') 6 | endif 7 | 8 | message('Documentation not built as building it while cross building is not supported yet.') 9 | subdir_done() 10 | endif 11 | 12 | required_hotdoc_extensions = ['gst-extension'] 13 | if gst_dep.type_name() == 'internal' 14 | gst_proj = subproject('gstreamer') 15 | plugins_cache_generator = gst_proj.get_variable('plugins_cache_generator') 16 | else 17 | plugins_cache_generator = find_program(join_paths(gst_dep.get_pkgconfig_variable('libexecdir'), 'gstreamer-' + api_version, 'gst-plugins-doc-cache-generator'), 18 | required: false) 19 | endif 20 | 21 | plugins_cache = join_paths(meson.current_source_dir(), 'gst_plugins_cache.json') 22 | if plugins_cache_generator.found() 23 | plugins_doc_dep = custom_target('libav-plugins-doc-cache', 24 | command: [plugins_cache_generator, plugins_cache, '@OUTPUT@', '@INPUT@'], 25 | input: plugins, 26 | output: 'gst_plugins_cache.json', 27 | build_always_stale: true, 28 | ) 29 | else 30 | warning('GStreamer plugin inspector for documentation not found, can\'t update the cache') 31 | endif 32 | 33 | hotdoc_p = find_program('hotdoc', required: get_option('doc')) 34 | if not hotdoc_p.found() 35 | message('Hotdoc not found, not building the documentation') 36 | subdir_done() 37 | endif 38 | 39 | hotdoc_req = '>= 0.11.0' 40 | hotdoc_version = run_command(hotdoc_p, '--version').stdout() 41 | if not hotdoc_version.version_compare(hotdoc_req) 42 | if get_option('doc').enabled() 43 | error('Hotdoc version @0@ not found, got @1@'.format(hotdoc_req, hotdoc_version)) 44 | else 45 | message('Hotdoc version @0@ not found, got @1@'.format(hotdoc_req, hotdoc_version)) 46 | subdir_done() 47 | endif 48 | endif 49 | 50 | build_hotdoc = true 51 | hotdoc = import('hotdoc') 52 | docconf = configuration_data() 53 | docconf.set('GST_API_VERSION', api_version) 54 | 55 | foreach extension: required_hotdoc_extensions 56 | if not hotdoc.has_extensions(extension) 57 | if get_option('doc').enabled() 58 | error('Documentation enabled but gi-extension missing') 59 | endif 60 | 61 | message('@0@ extensions not found, not building documentation requiring it'.format(extension)) 62 | subdir_done() 63 | endif 64 | endforeach 65 | 66 | 67 | libs_doc = [] 68 | plugins_doc = [hotdoc.generate_doc('libav', 69 | project_version: api_version, 70 | sitemap: 'sitemap.txt', 71 | index: 'index.md', 72 | gst_index: 'index.md', 73 | gst_smart_index: true, 74 | gst_c_sources: ['../ext/*/*.[ch]',], 75 | gst_cache_file: plugins_cache, 76 | gst_plugin_name: 'libav', 77 | dependencies: [gst_dep, gstlibav_plugin, plugins_doc_dep], 78 | disable_incremental_build: true, 79 | )] 80 | -------------------------------------------------------------------------------- /docs/sitemap.txt: -------------------------------------------------------------------------------- 1 | gst-index 2 | -------------------------------------------------------------------------------- /ext/libav/gstav.c: -------------------------------------------------------------------------------- 1 | /* GStreamer 2 | * Copyright (C) <1999> Erik Walthinsen 3 | * 4 | * This library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Library General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2 of the License, or (at your option) any later version. 8 | * 9 | * This library is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Library General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Library General Public 15 | * License along with this library; if not, write to the 16 | * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, 17 | * Boston, MA 02110-1301, USA. 18 | */ 19 | 20 | /* First, include the header file for the plugin, to bring in the 21 | * object definition and other useful things. 22 | */ 23 | 24 | #ifdef HAVE_CONFIG_H 25 | #include "config.h" 26 | #endif 27 | #include 28 | #include 29 | #include 30 | 31 | #include "gstav.h" 32 | #include "gstavutils.h" 33 | #include "gstavcfg.h" 34 | 35 | #ifdef GST_LIBAV_ENABLE_GPL 36 | #define LICENSE "GPL" 37 | #else 38 | #define LICENSE "LGPL" 39 | #endif 40 | 41 | GST_DEBUG_CATEGORY (ffmpeg_debug); 42 | 43 | static GMutex gst_avcodec_mutex; 44 | 45 | /* 46 | * Check for FFmpeg-provided libavcodec/format 47 | */ 48 | static inline gboolean 49 | gst_ffmpeg_avcodec_is_ffmpeg (void) 50 | { 51 | guint av_version = avcodec_version (); 52 | 53 | GST_DEBUG ("Using libavcodec version %d.%d.%d", 54 | av_version >> 16, (av_version & 0x00ff00) >> 8, av_version & 0xff); 55 | 56 | /* FFmpeg *_MICRO versions start at 100 and Libav's at 0 */ 57 | if ((av_version & 0xff) < 100) 58 | return FALSE; 59 | 60 | return TRUE; 61 | } 62 | 63 | int 64 | gst_ffmpeg_avcodec_open (AVCodecContext * avctx, AVCodec * codec) 65 | { 66 | int ret; 67 | 68 | g_mutex_lock (&gst_avcodec_mutex); 69 | ret = avcodec_open2 (avctx, codec, NULL); 70 | g_mutex_unlock (&gst_avcodec_mutex); 71 | 72 | return ret; 73 | } 74 | 75 | int 76 | gst_ffmpeg_avcodec_close (AVCodecContext * avctx) 77 | { 78 | int ret; 79 | 80 | g_mutex_lock (&gst_avcodec_mutex); 81 | ret = avcodec_close (avctx); 82 | g_mutex_unlock (&gst_avcodec_mutex); 83 | 84 | return ret; 85 | } 86 | 87 | int 88 | gst_ffmpeg_av_find_stream_info (AVFormatContext * ic) 89 | { 90 | int ret; 91 | 92 | g_mutex_lock (&gst_avcodec_mutex); 93 | ret = avformat_find_stream_info (ic, NULL); 94 | g_mutex_unlock (&gst_avcodec_mutex); 95 | 96 | return ret; 97 | } 98 | 99 | #ifndef GST_DISABLE_GST_DEBUG 100 | static void 101 | gst_ffmpeg_log_callback (void *ptr, int level, const char *fmt, va_list vl) 102 | { 103 | GstDebugLevel gst_level; 104 | gint len = strlen (fmt); 105 | gchar *fmt2 = NULL; 106 | 107 | switch (level) { 108 | case AV_LOG_QUIET: 109 | gst_level = GST_LEVEL_NONE; 110 | break; 111 | case AV_LOG_ERROR: 112 | gst_level = GST_LEVEL_ERROR; 113 | break; 114 | case AV_LOG_INFO: 115 | gst_level = GST_LEVEL_INFO; 116 | break; 117 | case AV_LOG_DEBUG: 118 | gst_level = GST_LEVEL_DEBUG; 119 | break; 120 | default: 121 | gst_level = GST_LEVEL_INFO; 122 | break; 123 | } 124 | 125 | /* remove trailing newline as it gets already appended by the logger */ 126 | if (fmt[len - 1] == '\n') { 127 | fmt2 = g_strdup (fmt); 128 | fmt2[len - 1] = '\0'; 129 | } 130 | 131 | gst_debug_log_valist (ffmpeg_debug, gst_level, "", "", 0, NULL, 132 | fmt2 ? fmt2 : fmt, vl); 133 | 134 | g_free (fmt2); 135 | } 136 | #endif 137 | 138 | static gboolean 139 | plugin_init (GstPlugin * plugin) 140 | { 141 | GST_DEBUG_CATEGORY_INIT (ffmpeg_debug, "libav", 0, "libav elements"); 142 | 143 | /* Bail if not FFmpeg. We can no longer ensure operation with Libav */ 144 | if (!gst_ffmpeg_avcodec_is_ffmpeg ()) { 145 | GST_ERROR_OBJECT (plugin, 146 | "Incompatible, non-FFmpeg libavcodec/format found"); 147 | return FALSE; 148 | } 149 | #ifndef GST_DISABLE_GST_DEBUG 150 | av_log_set_callback (gst_ffmpeg_log_callback); 151 | #endif 152 | 153 | gst_ffmpeg_init_pix_fmt_info (); 154 | 155 | /* build global ffmpeg param/property info */ 156 | gst_ffmpeg_cfg_init (); 157 | 158 | gst_ffmpegaudenc_register (plugin); 159 | gst_ffmpegvidenc_register (plugin); 160 | gst_ffmpegauddec_register (plugin); 161 | gst_ffmpegviddec_register (plugin); 162 | gst_ffmpegdemux_register (plugin); 163 | gst_ffmpegmux_register (plugin); 164 | gst_ffmpegdeinterlace_register (plugin); 165 | 166 | /* Now we can return the pointer to the newly created Plugin object. */ 167 | return TRUE; 168 | } 169 | 170 | GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, 171 | GST_VERSION_MINOR, 172 | libav, 173 | "All libav codecs and formats (" LIBAV_SOURCE ")", 174 | plugin_init, PACKAGE_VERSION, LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN) 175 | -------------------------------------------------------------------------------- /ext/libav/gstav.h: -------------------------------------------------------------------------------- 1 | /* GStreamer 2 | * Copyright (C) <1999> Erik Walthinsen 3 | * 4 | * This library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Library General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2 of the License, or (at your option) any later version. 8 | * 9 | * This library is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Library General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Library General Public 15 | * License along with this library; if not, write to the 16 | * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, 17 | * Boston, MA 02110-1301, USA. 18 | */ 19 | 20 | /* First, include the header file for the plugin, to bring in the 21 | * object definition and other useful things. 22 | */ 23 | 24 | #ifndef __GST_FFMPEG_H__ 25 | #define __GST_FFMPEG_H__ 26 | 27 | #include 28 | #include 29 | 30 | #include 31 | #include 32 | #include 33 | 34 | GST_DEBUG_CATEGORY_EXTERN (ffmpeg_debug); 35 | #define GST_CAT_DEFAULT ffmpeg_debug 36 | 37 | G_BEGIN_DECLS 38 | 39 | extern gboolean gst_ffmpegdemux_register (GstPlugin * plugin); 40 | extern gboolean gst_ffmpegauddec_register (GstPlugin * plugin); 41 | extern gboolean gst_ffmpegviddec_register (GstPlugin * plugin); 42 | extern gboolean gst_ffmpegaudenc_register (GstPlugin * plugin); 43 | extern gboolean gst_ffmpegvidenc_register (GstPlugin * plugin); 44 | extern gboolean gst_ffmpegmux_register (GstPlugin * plugin); 45 | extern gboolean gst_ffmpegdeinterlace_register (GstPlugin * plugin); 46 | 47 | int gst_ffmpeg_avcodec_open (AVCodecContext *avctx, AVCodec *codec); 48 | int gst_ffmpeg_avcodec_close (AVCodecContext *avctx); 49 | int gst_ffmpeg_av_find_stream_info(AVFormatContext *ic); 50 | 51 | G_END_DECLS 52 | 53 | /* use GST_FFMPEG URL_STREAMHEADER with URL_WRONLY if the first 54 | * buffer should be used as streamheader property on the pad's caps. */ 55 | #define GST_FFMPEG_URL_STREAMHEADER 16 56 | 57 | #endif /* __GST_FFMPEG_H__ */ 58 | -------------------------------------------------------------------------------- /ext/libav/gstavauddec.h: -------------------------------------------------------------------------------- 1 | /* GStreamer 2 | * Copyright (C) <1999> Erik Walthinsen 3 | * 4 | * This library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Library General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2 of the License, or (at your option) any later version. 8 | * 9 | * This library is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Library General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Library General Public 15 | * License along with this library; if not, write to the 16 | * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, 17 | * Boston, MA 02110-1301, USA. 18 | */ 19 | #ifndef __GST_FFMPEGAUDDEC_H__ 20 | #define __GST_FFMPEGAUDDEC_H__ 21 | 22 | #include 23 | 24 | G_BEGIN_DECLS 25 | 26 | #include 27 | #include 28 | #include 29 | 30 | typedef struct _GstFFMpegAudDec GstFFMpegAudDec; 31 | struct _GstFFMpegAudDec 32 | { 33 | GstAudioDecoder parent; 34 | 35 | /* decoding */ 36 | AVCodecContext *context; 37 | gboolean opened; 38 | 39 | AVFrame *frame; 40 | 41 | guint8 *padded; 42 | gint padded_size; 43 | 44 | /* prevent reopening the decoder on GST_EVENT_CAPS when caps are same as last time. */ 45 | GstCaps *last_caps; 46 | 47 | /* current output format */ 48 | GstAudioInfo info; 49 | GstAudioChannelPosition ffmpeg_layout[64]; 50 | gboolean needs_reorder; 51 | }; 52 | 53 | typedef struct _GstFFMpegAudDecClass GstFFMpegAudDecClass; 54 | 55 | struct _GstFFMpegAudDecClass 56 | { 57 | GstAudioDecoderClass parent_class; 58 | 59 | AVCodec *in_plugin; 60 | GstPadTemplate *srctempl, *sinktempl; 61 | }; 62 | 63 | #define GST_TYPE_FFMPEGDEC \ 64 | (gst_ffmpegauddec_get_type()) 65 | #define GST_FFMPEGDEC(obj) \ 66 | (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_FFMPEGDEC,GstFFMpegAudDec)) 67 | #define GST_FFMPEGAUDDEC_CLASS(klass) \ 68 | (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_FFMPEGDEC,GstFFMpegAudDecClass)) 69 | #define GST_IS_FFMPEGDEC(obj) \ 70 | (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_FFMPEGDEC)) 71 | #define GST_IS_FFMPEGAUDDEC_CLASS(klass) \ 72 | (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_FFMPEGDEC)) 73 | 74 | G_END_DECLS 75 | 76 | #endif 77 | -------------------------------------------------------------------------------- /ext/libav/gstavaudenc.c: -------------------------------------------------------------------------------- 1 | /* GStreamer 2 | * Copyright (C) <1999> Erik Walthinsen 3 | * Copyright (C) <2012> Collabora Ltd. 4 | * Author: Sebastian Dröge 5 | * 6 | * This library is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Library General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 2 of the License, or (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Library General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Library General Public 17 | * License along with this library; if not, write to the 18 | * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, 19 | * Boston, MA 02110-1301, USA. 20 | */ 21 | 22 | #ifdef HAVE_CONFIG_H 23 | #include "config.h" 24 | #endif 25 | 26 | #include 27 | #include 28 | /* for stats file handling */ 29 | #include 30 | #include 31 | #include 32 | 33 | #include 34 | #include 35 | 36 | #include 37 | 38 | #include "gstav.h" 39 | #include "gstavcfg.h" 40 | #include "gstavcodecmap.h" 41 | #include "gstavutils.h" 42 | #include "gstavaudenc.h" 43 | 44 | enum 45 | { 46 | PROP_0, 47 | PROP_CFG_BASE, 48 | }; 49 | 50 | static void gst_ffmpegaudenc_class_init (GstFFMpegAudEncClass * klass); 51 | static void gst_ffmpegaudenc_base_init (GstFFMpegAudEncClass * klass); 52 | static void gst_ffmpegaudenc_init (GstFFMpegAudEnc * ffmpegaudenc); 53 | static void gst_ffmpegaudenc_finalize (GObject * object); 54 | 55 | static gboolean gst_ffmpegaudenc_set_format (GstAudioEncoder * encoder, 56 | GstAudioInfo * info); 57 | static GstFlowReturn gst_ffmpegaudenc_handle_frame (GstAudioEncoder * encoder, 58 | GstBuffer * inbuf); 59 | static gboolean gst_ffmpegaudenc_start (GstAudioEncoder * encoder); 60 | static gboolean gst_ffmpegaudenc_stop (GstAudioEncoder * encoder); 61 | static void gst_ffmpegaudenc_flush (GstAudioEncoder * encoder); 62 | 63 | static void gst_ffmpegaudenc_set_property (GObject * object, 64 | guint prop_id, const GValue * value, GParamSpec * pspec); 65 | static void gst_ffmpegaudenc_get_property (GObject * object, 66 | guint prop_id, GValue * value, GParamSpec * pspec); 67 | 68 | #define GST_FFENC_PARAMS_QDATA g_quark_from_static_string("avenc-params") 69 | 70 | static GstElementClass *parent_class = NULL; 71 | 72 | static void 73 | gst_ffmpegaudenc_base_init (GstFFMpegAudEncClass * klass) 74 | { 75 | GstElementClass *element_class = GST_ELEMENT_CLASS (klass); 76 | AVCodec *in_plugin; 77 | GstPadTemplate *srctempl = NULL, *sinktempl = NULL; 78 | GstCaps *srccaps = NULL, *sinkcaps = NULL; 79 | gchar *longname, *description; 80 | 81 | in_plugin = 82 | (AVCodec *) g_type_get_qdata (G_OBJECT_CLASS_TYPE (klass), 83 | GST_FFENC_PARAMS_QDATA); 84 | g_assert (in_plugin != NULL); 85 | 86 | /* construct the element details struct */ 87 | longname = g_strdup_printf ("libav %s encoder", in_plugin->long_name); 88 | description = g_strdup_printf ("libav %s encoder", in_plugin->name); 89 | gst_element_class_set_metadata (element_class, longname, 90 | "Codec/Encoder/Audio", description, 91 | "Wim Taymans , " 92 | "Ronald Bultje "); 93 | g_free (longname); 94 | g_free (description); 95 | 96 | if (!(srccaps = gst_ffmpeg_codecid_to_caps (in_plugin->id, NULL, TRUE))) { 97 | GST_DEBUG ("Couldn't get source caps for encoder '%s'", in_plugin->name); 98 | srccaps = gst_caps_new_empty_simple ("unknown/unknown"); 99 | } 100 | 101 | sinkcaps = gst_ffmpeg_codectype_to_audio_caps (NULL, 102 | in_plugin->id, TRUE, in_plugin); 103 | if (!sinkcaps) { 104 | GST_DEBUG ("Couldn't get sink caps for encoder '%s'", in_plugin->name); 105 | sinkcaps = gst_caps_new_empty_simple ("unknown/unknown"); 106 | } 107 | 108 | /* pad templates */ 109 | sinktempl = gst_pad_template_new ("sink", GST_PAD_SINK, 110 | GST_PAD_ALWAYS, sinkcaps); 111 | srctempl = gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS, srccaps); 112 | 113 | gst_element_class_add_pad_template (element_class, srctempl); 114 | gst_element_class_add_pad_template (element_class, sinktempl); 115 | 116 | gst_caps_unref (sinkcaps); 117 | gst_caps_unref (srccaps); 118 | 119 | klass->in_plugin = in_plugin; 120 | klass->srctempl = srctempl; 121 | klass->sinktempl = sinktempl; 122 | 123 | return; 124 | } 125 | 126 | static void 127 | gst_ffmpegaudenc_class_init (GstFFMpegAudEncClass * klass) 128 | { 129 | GObjectClass *gobject_class; 130 | GstAudioEncoderClass *gstaudioencoder_class; 131 | 132 | gobject_class = (GObjectClass *) klass; 133 | gstaudioencoder_class = (GstAudioEncoderClass *) klass; 134 | 135 | parent_class = g_type_class_peek_parent (klass); 136 | 137 | gobject_class->set_property = gst_ffmpegaudenc_set_property; 138 | gobject_class->get_property = gst_ffmpegaudenc_get_property; 139 | 140 | gst_ffmpeg_cfg_install_properties (gobject_class, klass->in_plugin, 141 | PROP_CFG_BASE, AV_OPT_FLAG_ENCODING_PARAM | AV_OPT_FLAG_AUDIO_PARAM); 142 | 143 | gobject_class->finalize = gst_ffmpegaudenc_finalize; 144 | 145 | gstaudioencoder_class->start = GST_DEBUG_FUNCPTR (gst_ffmpegaudenc_start); 146 | gstaudioencoder_class->stop = GST_DEBUG_FUNCPTR (gst_ffmpegaudenc_stop); 147 | gstaudioencoder_class->flush = GST_DEBUG_FUNCPTR (gst_ffmpegaudenc_flush); 148 | gstaudioencoder_class->set_format = 149 | GST_DEBUG_FUNCPTR (gst_ffmpegaudenc_set_format); 150 | gstaudioencoder_class->handle_frame = 151 | GST_DEBUG_FUNCPTR (gst_ffmpegaudenc_handle_frame); 152 | } 153 | 154 | static void 155 | gst_ffmpegaudenc_init (GstFFMpegAudEnc * ffmpegaudenc) 156 | { 157 | GstFFMpegAudEncClass *klass = 158 | (GstFFMpegAudEncClass *) G_OBJECT_GET_CLASS (ffmpegaudenc); 159 | 160 | GST_PAD_SET_ACCEPT_TEMPLATE (GST_AUDIO_ENCODER_SINK_PAD (ffmpegaudenc)); 161 | 162 | /* ffmpeg objects */ 163 | ffmpegaudenc->context = avcodec_alloc_context3 (klass->in_plugin); 164 | ffmpegaudenc->refcontext = avcodec_alloc_context3 (klass->in_plugin); 165 | ffmpegaudenc->opened = FALSE; 166 | ffmpegaudenc->frame = av_frame_alloc (); 167 | 168 | gst_audio_encoder_set_drainable (GST_AUDIO_ENCODER (ffmpegaudenc), TRUE); 169 | } 170 | 171 | static void 172 | gst_ffmpegaudenc_finalize (GObject * object) 173 | { 174 | GstFFMpegAudEnc *ffmpegaudenc = (GstFFMpegAudEnc *) object; 175 | 176 | /* clean up remaining allocated data */ 177 | av_frame_free (&ffmpegaudenc->frame); 178 | gst_ffmpeg_avcodec_close (ffmpegaudenc->context); 179 | gst_ffmpeg_avcodec_close (ffmpegaudenc->refcontext); 180 | av_free (ffmpegaudenc->context); 181 | av_free (ffmpegaudenc->refcontext); 182 | 183 | G_OBJECT_CLASS (parent_class)->finalize (object); 184 | } 185 | 186 | static gboolean 187 | gst_ffmpegaudenc_start (GstAudioEncoder * encoder) 188 | { 189 | GstFFMpegAudEnc *ffmpegaudenc = (GstFFMpegAudEnc *) encoder; 190 | GstFFMpegAudEncClass *oclass = 191 | (GstFFMpegAudEncClass *) G_OBJECT_GET_CLASS (ffmpegaudenc); 192 | 193 | ffmpegaudenc->opened = FALSE; 194 | ffmpegaudenc->need_reopen = FALSE; 195 | 196 | gst_ffmpeg_avcodec_close (ffmpegaudenc->context); 197 | if (avcodec_get_context_defaults3 (ffmpegaudenc->context, 198 | oclass->in_plugin) < 0) { 199 | GST_DEBUG_OBJECT (ffmpegaudenc, "Failed to set context defaults"); 200 | return FALSE; 201 | } 202 | 203 | return TRUE; 204 | } 205 | 206 | static gboolean 207 | gst_ffmpegaudenc_stop (GstAudioEncoder * encoder) 208 | { 209 | GstFFMpegAudEnc *ffmpegaudenc = (GstFFMpegAudEnc *) encoder; 210 | 211 | /* close old session */ 212 | gst_ffmpeg_avcodec_close (ffmpegaudenc->context); 213 | ffmpegaudenc->opened = FALSE; 214 | ffmpegaudenc->need_reopen = FALSE; 215 | 216 | return TRUE; 217 | } 218 | 219 | static void 220 | gst_ffmpegaudenc_flush (GstAudioEncoder * encoder) 221 | { 222 | GstFFMpegAudEnc *ffmpegaudenc = (GstFFMpegAudEnc *) encoder; 223 | 224 | if (ffmpegaudenc->opened) { 225 | avcodec_flush_buffers (ffmpegaudenc->context); 226 | } 227 | } 228 | 229 | static gboolean 230 | gst_ffmpegaudenc_set_format (GstAudioEncoder * encoder, GstAudioInfo * info) 231 | { 232 | GstFFMpegAudEnc *ffmpegaudenc = (GstFFMpegAudEnc *) encoder; 233 | GstCaps *other_caps; 234 | GstCaps *allowed_caps; 235 | GstCaps *icaps; 236 | gsize frame_size; 237 | GstFFMpegAudEncClass *oclass = 238 | (GstFFMpegAudEncClass *) G_OBJECT_GET_CLASS (ffmpegaudenc); 239 | 240 | ffmpegaudenc->need_reopen = FALSE; 241 | 242 | /* close old session */ 243 | if (ffmpegaudenc->opened) { 244 | gst_ffmpeg_avcodec_close (ffmpegaudenc->context); 245 | ffmpegaudenc->opened = FALSE; 246 | if (avcodec_get_context_defaults3 (ffmpegaudenc->context, 247 | oclass->in_plugin) < 0) { 248 | GST_DEBUG_OBJECT (ffmpegaudenc, "Failed to set context defaults"); 249 | return FALSE; 250 | } 251 | } 252 | 253 | gst_ffmpeg_cfg_fill_context (G_OBJECT (ffmpegaudenc), ffmpegaudenc->context); 254 | 255 | /* fetch pix_fmt and so on */ 256 | gst_ffmpeg_audioinfo_to_context (info, ffmpegaudenc->context); 257 | if (!ffmpegaudenc->context->time_base.den) { 258 | ffmpegaudenc->context->time_base.den = GST_AUDIO_INFO_RATE (info); 259 | ffmpegaudenc->context->time_base.num = 1; 260 | ffmpegaudenc->context->ticks_per_frame = 1; 261 | } 262 | 263 | if (ffmpegaudenc->context->channel_layout) { 264 | gst_ffmpeg_channel_layout_to_gst (ffmpegaudenc->context->channel_layout, 265 | ffmpegaudenc->context->channels, ffmpegaudenc->ffmpeg_layout); 266 | ffmpegaudenc->needs_reorder = 267 | (memcmp (ffmpegaudenc->ffmpeg_layout, info->position, 268 | sizeof (GstAudioChannelPosition) * 269 | ffmpegaudenc->context->channels) != 0); 270 | } 271 | 272 | /* some codecs support more than one format, first auto-choose one */ 273 | GST_DEBUG_OBJECT (ffmpegaudenc, "picking an output format ..."); 274 | allowed_caps = gst_pad_get_allowed_caps (GST_AUDIO_ENCODER_SRC_PAD (encoder)); 275 | if (!allowed_caps) { 276 | GST_DEBUG_OBJECT (ffmpegaudenc, "... but no peer, using template caps"); 277 | /* we need to copy because get_allowed_caps returns a ref, and 278 | * get_pad_template_caps doesn't */ 279 | allowed_caps = 280 | gst_pad_get_pad_template_caps (GST_AUDIO_ENCODER_SRC_PAD (encoder)); 281 | } 282 | GST_DEBUG_OBJECT (ffmpegaudenc, "chose caps %" GST_PTR_FORMAT, allowed_caps); 283 | gst_ffmpeg_caps_with_codecid (oclass->in_plugin->id, 284 | oclass->in_plugin->type, allowed_caps, ffmpegaudenc->context); 285 | 286 | /* open codec */ 287 | if (gst_ffmpeg_avcodec_open (ffmpegaudenc->context, oclass->in_plugin) < 0) { 288 | gst_caps_unref (allowed_caps); 289 | gst_ffmpeg_avcodec_close (ffmpegaudenc->context); 290 | GST_DEBUG_OBJECT (ffmpegaudenc, "avenc_%s: Failed to open FFMPEG codec", 291 | oclass->in_plugin->name); 292 | if (avcodec_get_context_defaults3 (ffmpegaudenc->context, 293 | oclass->in_plugin) < 0) 294 | GST_DEBUG_OBJECT (ffmpegaudenc, "Failed to set context defaults"); 295 | 296 | if ((oclass->in_plugin->capabilities & AV_CODEC_CAP_EXPERIMENTAL) && 297 | ffmpegaudenc->context->strict_std_compliance != 298 | FF_COMPLIANCE_EXPERIMENTAL) { 299 | GST_ELEMENT_ERROR (ffmpegaudenc, LIBRARY, SETTINGS, 300 | ("Codec is experimental, but settings don't allow encoders to " 301 | "produce output of experimental quality"), 302 | ("This codec may not create output that is conformant to the specs " 303 | "or of good quality. If you must use it anyway, set the " 304 | "compliance property to experimental")); 305 | } 306 | return FALSE; 307 | } 308 | 309 | /* try to set this caps on the other side */ 310 | other_caps = gst_ffmpeg_codecid_to_caps (oclass->in_plugin->id, 311 | ffmpegaudenc->context, TRUE); 312 | 313 | if (!other_caps) { 314 | gst_caps_unref (allowed_caps); 315 | gst_ffmpeg_avcodec_close (ffmpegaudenc->context); 316 | GST_DEBUG ("Unsupported codec - no caps found"); 317 | if (avcodec_get_context_defaults3 (ffmpegaudenc->context, 318 | oclass->in_plugin) < 0) 319 | GST_DEBUG_OBJECT (ffmpegaudenc, "Failed to set context defaults"); 320 | return FALSE; 321 | } 322 | 323 | icaps = gst_caps_intersect (allowed_caps, other_caps); 324 | gst_caps_unref (allowed_caps); 325 | gst_caps_unref (other_caps); 326 | if (gst_caps_is_empty (icaps)) { 327 | gst_caps_unref (icaps); 328 | return FALSE; 329 | } 330 | icaps = gst_caps_fixate (icaps); 331 | 332 | if (!gst_audio_encoder_set_output_format (GST_AUDIO_ENCODER (ffmpegaudenc), 333 | icaps)) { 334 | gst_ffmpeg_avcodec_close (ffmpegaudenc->context); 335 | gst_caps_unref (icaps); 336 | if (avcodec_get_context_defaults3 (ffmpegaudenc->context, 337 | oclass->in_plugin) < 0) 338 | GST_DEBUG_OBJECT (ffmpegaudenc, "Failed to set context defaults"); 339 | return FALSE; 340 | } 341 | gst_caps_unref (icaps); 342 | 343 | frame_size = ffmpegaudenc->context->frame_size; 344 | if (frame_size > 1) { 345 | gst_audio_encoder_set_frame_samples_min (GST_AUDIO_ENCODER (ffmpegaudenc), 346 | frame_size); 347 | gst_audio_encoder_set_frame_samples_max (GST_AUDIO_ENCODER (ffmpegaudenc), 348 | frame_size); 349 | gst_audio_encoder_set_frame_max (GST_AUDIO_ENCODER (ffmpegaudenc), 1); 350 | } else { 351 | gst_audio_encoder_set_frame_samples_min (GST_AUDIO_ENCODER (ffmpegaudenc), 352 | 0); 353 | gst_audio_encoder_set_frame_samples_max (GST_AUDIO_ENCODER (ffmpegaudenc), 354 | 0); 355 | gst_audio_encoder_set_frame_max (GST_AUDIO_ENCODER (ffmpegaudenc), 0); 356 | } 357 | 358 | /* Store some tags */ 359 | { 360 | GstTagList *tags = gst_tag_list_new_empty (); 361 | const gchar *codec; 362 | 363 | gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_NOMINAL_BITRATE, 364 | (guint) ffmpegaudenc->context->bit_rate, NULL); 365 | 366 | if ((codec = 367 | gst_ffmpeg_get_codecid_longname (ffmpegaudenc->context->codec_id))) 368 | gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_AUDIO_CODEC, codec, 369 | NULL); 370 | 371 | gst_audio_encoder_merge_tags (encoder, tags, GST_TAG_MERGE_REPLACE); 372 | gst_tag_list_unref (tags); 373 | } 374 | 375 | /* success! */ 376 | ffmpegaudenc->opened = TRUE; 377 | ffmpegaudenc->need_reopen = FALSE; 378 | 379 | return TRUE; 380 | } 381 | 382 | static void 383 | gst_ffmpegaudenc_free_avpacket (gpointer pkt) 384 | { 385 | av_packet_unref ((AVPacket *) pkt); 386 | g_slice_free (AVPacket, pkt); 387 | } 388 | 389 | typedef struct 390 | { 391 | GstBuffer *buffer; 392 | GstMapInfo map; 393 | 394 | guint8 **ext_data_array, *ext_data; 395 | } BufferInfo; 396 | 397 | static void 398 | buffer_info_free (void *opaque, guint8 * data) 399 | { 400 | BufferInfo *info = opaque; 401 | 402 | if (info->buffer) { 403 | gst_buffer_unmap (info->buffer, &info->map); 404 | gst_buffer_unref (info->buffer); 405 | } else { 406 | av_free (info->ext_data); 407 | av_free (info->ext_data_array); 408 | } 409 | g_slice_free (BufferInfo, info); 410 | } 411 | 412 | static GstFlowReturn 413 | gst_ffmpegaudenc_send_frame (GstFFMpegAudEnc * ffmpegaudenc, GstBuffer * buffer) 414 | { 415 | GstAudioEncoder *enc; 416 | AVCodecContext *ctx; 417 | GstFlowReturn ret; 418 | gint res; 419 | GstAudioInfo *info; 420 | AVFrame *frame = ffmpegaudenc->frame; 421 | gboolean planar; 422 | gint nsamples = -1; 423 | 424 | enc = GST_AUDIO_ENCODER (ffmpegaudenc); 425 | 426 | ctx = ffmpegaudenc->context; 427 | 428 | if (buffer != NULL) { 429 | BufferInfo *buffer_info = g_slice_new0 (BufferInfo); 430 | guint8 *audio_in; 431 | guint in_size; 432 | 433 | buffer_info->buffer = buffer; 434 | gst_buffer_map (buffer, &buffer_info->map, GST_MAP_READ); 435 | audio_in = buffer_info->map.data; 436 | in_size = buffer_info->map.size; 437 | 438 | GST_LOG_OBJECT (ffmpegaudenc, "encoding buffer %p size:%u", audio_in, 439 | in_size); 440 | 441 | info = gst_audio_encoder_get_audio_info (enc); 442 | planar = av_sample_fmt_is_planar (ffmpegaudenc->context->sample_fmt); 443 | frame->format = ffmpegaudenc->context->sample_fmt; 444 | frame->sample_rate = ffmpegaudenc->context->sample_rate; 445 | frame->channels = ffmpegaudenc->context->channels; 446 | frame->channel_layout = ffmpegaudenc->context->channel_layout; 447 | 448 | if (planar && info->channels > 1) { 449 | gint channels; 450 | gint i, j; 451 | 452 | nsamples = frame->nb_samples = in_size / info->bpf; 453 | channels = info->channels; 454 | 455 | frame->buf[0] = 456 | av_buffer_create (NULL, 0, buffer_info_free, buffer_info, 0); 457 | 458 | if (info->channels > AV_NUM_DATA_POINTERS) { 459 | buffer_info->ext_data_array = frame->extended_data = 460 | av_malloc_array (info->channels, sizeof (uint8_t *)); 461 | } else { 462 | frame->extended_data = frame->data; 463 | } 464 | 465 | buffer_info->ext_data = frame->extended_data[0] = av_malloc (in_size); 466 | frame->linesize[0] = in_size / channels; 467 | for (i = 1; i < channels; i++) 468 | frame->extended_data[i] = 469 | frame->extended_data[i - 1] + frame->linesize[0]; 470 | 471 | switch (info->finfo->width) { 472 | case 8:{ 473 | const guint8 *idata = (const guint8 *) audio_in; 474 | 475 | for (i = 0; i < nsamples; i++) { 476 | for (j = 0; j < channels; j++) { 477 | ((guint8 *) frame->extended_data[j])[i] = idata[j]; 478 | } 479 | idata += channels; 480 | } 481 | break; 482 | } 483 | case 16:{ 484 | const guint16 *idata = (const guint16 *) audio_in; 485 | 486 | for (i = 0; i < nsamples; i++) { 487 | for (j = 0; j < channels; j++) { 488 | ((guint16 *) frame->extended_data[j])[i] = idata[j]; 489 | } 490 | idata += channels; 491 | } 492 | break; 493 | } 494 | case 32:{ 495 | const guint32 *idata = (const guint32 *) audio_in; 496 | 497 | for (i = 0; i < nsamples; i++) { 498 | for (j = 0; j < channels; j++) { 499 | ((guint32 *) frame->extended_data[j])[i] = idata[j]; 500 | } 501 | idata += channels; 502 | } 503 | 504 | break; 505 | } 506 | case 64:{ 507 | const guint64 *idata = (const guint64 *) audio_in; 508 | 509 | for (i = 0; i < nsamples; i++) { 510 | for (j = 0; j < channels; j++) { 511 | ((guint64 *) frame->extended_data[j])[i] = idata[j]; 512 | } 513 | idata += channels; 514 | } 515 | 516 | break; 517 | } 518 | default: 519 | g_assert_not_reached (); 520 | break; 521 | } 522 | 523 | gst_buffer_unmap (buffer, &buffer_info->map); 524 | gst_buffer_unref (buffer); 525 | buffer_info->buffer = NULL; 526 | } else { 527 | frame->data[0] = audio_in; 528 | frame->extended_data = frame->data; 529 | frame->linesize[0] = in_size; 530 | frame->nb_samples = nsamples = in_size / info->bpf; 531 | frame->buf[0] = 532 | av_buffer_create (NULL, 0, buffer_info_free, buffer_info, 0); 533 | } 534 | 535 | /* we have a frame to feed the encoder */ 536 | res = avcodec_send_frame (ctx, frame); 537 | 538 | av_frame_unref (frame); 539 | } else { 540 | GstFFMpegAudEncClass *oclass = 541 | (GstFFMpegAudEncClass *) G_OBJECT_GET_CLASS (ffmpegaudenc); 542 | 543 | GST_LOG_OBJECT (ffmpegaudenc, "draining"); 544 | /* flushing the encoder */ 545 | res = avcodec_send_frame (ctx, NULL); 546 | 547 | /* If AV_CODEC_CAP_ENCODER_FLUSH wasn't set, we need to re-open 548 | * encoder */ 549 | if (!(oclass->in_plugin->capabilities & AV_CODEC_CAP_ENCODER_FLUSH)) { 550 | GST_DEBUG_OBJECT (ffmpegaudenc, "Encoder needs reopen later"); 551 | 552 | /* we will reopen later handle_frame() */ 553 | ffmpegaudenc->need_reopen = TRUE; 554 | } 555 | } 556 | 557 | if (res == 0) { 558 | ret = GST_FLOW_OK; 559 | } else if (res == AVERROR_EOF) { 560 | ret = GST_FLOW_EOS; 561 | } else { /* Any other return value is an error in our context */ 562 | ret = GST_FLOW_OK; 563 | GST_WARNING_OBJECT (ffmpegaudenc, "Failed to encode buffer"); 564 | } 565 | 566 | return ret; 567 | } 568 | 569 | static GstFlowReturn 570 | gst_ffmpegaudenc_receive_packet (GstFFMpegAudEnc * ffmpegaudenc, 571 | gboolean * got_packet) 572 | { 573 | GstAudioEncoder *enc; 574 | AVCodecContext *ctx; 575 | gint res; 576 | GstFlowReturn ret; 577 | AVPacket *pkt; 578 | 579 | enc = GST_AUDIO_ENCODER (ffmpegaudenc); 580 | 581 | ctx = ffmpegaudenc->context; 582 | 583 | pkt = g_slice_new0 (AVPacket); 584 | 585 | res = avcodec_receive_packet (ctx, pkt); 586 | 587 | if (res == 0) { 588 | GstBuffer *outbuf; 589 | 590 | GST_LOG_OBJECT (ffmpegaudenc, "pushing size %d", pkt->size); 591 | 592 | outbuf = 593 | gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY, pkt->data, 594 | pkt->size, 0, pkt->size, pkt, gst_ffmpegaudenc_free_avpacket); 595 | 596 | ret = 597 | gst_audio_encoder_finish_frame (enc, outbuf, 598 | pkt->duration > 0 ? pkt->duration : -1); 599 | *got_packet = TRUE; 600 | } else { 601 | GST_LOG_OBJECT (ffmpegaudenc, "no output produced"); 602 | g_slice_free (AVPacket, pkt); 603 | ret = GST_FLOW_OK; 604 | *got_packet = FALSE; 605 | } 606 | 607 | return ret; 608 | } 609 | 610 | static GstFlowReturn 611 | gst_ffmpegaudenc_drain (GstFFMpegAudEnc * ffmpegaudenc) 612 | { 613 | GstFlowReturn ret = GST_FLOW_OK; 614 | gboolean got_packet; 615 | 616 | ret = gst_ffmpegaudenc_send_frame (ffmpegaudenc, NULL); 617 | 618 | if (ret == GST_FLOW_OK) { 619 | do { 620 | ret = gst_ffmpegaudenc_receive_packet (ffmpegaudenc, &got_packet); 621 | if (ret != GST_FLOW_OK) 622 | break; 623 | } while (got_packet); 624 | } 625 | 626 | /* NOTE: this may or may not work depending on capability */ 627 | avcodec_flush_buffers (ffmpegaudenc->context); 628 | 629 | /* FFMpeg will return AVERROR_EOF if it's internal was fully drained 630 | * then we are translating it to GST_FLOW_EOS. However, because this behavior 631 | * is fully internal stuff of this implementation and gstaudioencoder 632 | * baseclass doesn't convert this GST_FLOW_EOS to GST_FLOW_OK, 633 | * convert this flow returned here */ 634 | if (ret == GST_FLOW_EOS) 635 | ret = GST_FLOW_OK; 636 | 637 | return ret; 638 | } 639 | 640 | static GstFlowReturn 641 | gst_ffmpegaudenc_handle_frame (GstAudioEncoder * encoder, GstBuffer * inbuf) 642 | { 643 | GstFFMpegAudEnc *ffmpegaudenc; 644 | GstFlowReturn ret; 645 | gboolean got_packet; 646 | 647 | ffmpegaudenc = (GstFFMpegAudEnc *) encoder; 648 | 649 | if (G_UNLIKELY (!ffmpegaudenc->opened)) 650 | goto not_negotiated; 651 | 652 | if (!inbuf) 653 | return gst_ffmpegaudenc_drain (ffmpegaudenc); 654 | 655 | /* endoder was drained or flushed, and ffmpeg encoder doesn't support 656 | * flushing. We need to re-open encoder then */ 657 | if (ffmpegaudenc->need_reopen) { 658 | GST_DEBUG_OBJECT (ffmpegaudenc, "Open encoder again"); 659 | 660 | if (!gst_ffmpegaudenc_set_format (encoder, 661 | gst_audio_encoder_get_audio_info (encoder))) { 662 | GST_ERROR_OBJECT (ffmpegaudenc, "Couldn't re-open encoder"); 663 | return GST_FLOW_NOT_NEGOTIATED; 664 | } 665 | } 666 | 667 | inbuf = gst_buffer_ref (inbuf); 668 | 669 | GST_DEBUG_OBJECT (ffmpegaudenc, 670 | "Received time %" GST_TIME_FORMAT ", duration %" GST_TIME_FORMAT 671 | ", size %" G_GSIZE_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (inbuf)), 672 | GST_TIME_ARGS (GST_BUFFER_DURATION (inbuf)), gst_buffer_get_size (inbuf)); 673 | 674 | /* Reorder channels to the GStreamer channel order */ 675 | if (ffmpegaudenc->needs_reorder) { 676 | GstAudioInfo *info = gst_audio_encoder_get_audio_info (encoder); 677 | 678 | inbuf = gst_buffer_make_writable (inbuf); 679 | gst_audio_buffer_reorder_channels (inbuf, info->finfo->format, 680 | info->channels, info->position, ffmpegaudenc->ffmpeg_layout); 681 | } 682 | 683 | ret = gst_ffmpegaudenc_send_frame (ffmpegaudenc, inbuf); 684 | 685 | if (ret != GST_FLOW_OK) 686 | goto send_frame_failed; 687 | 688 | do { 689 | ret = gst_ffmpegaudenc_receive_packet (ffmpegaudenc, &got_packet); 690 | } while (got_packet); 691 | 692 | return GST_FLOW_OK; 693 | 694 | /* ERRORS */ 695 | not_negotiated: 696 | { 697 | GST_ELEMENT_ERROR (ffmpegaudenc, CORE, NEGOTIATION, (NULL), 698 | ("not configured to input format before data start")); 699 | gst_buffer_unref (inbuf); 700 | return GST_FLOW_NOT_NEGOTIATED; 701 | } 702 | send_frame_failed: 703 | { 704 | GST_DEBUG_OBJECT (ffmpegaudenc, "Failed to send frame %d (%s)", ret, 705 | gst_flow_get_name (ret)); 706 | return ret; 707 | } 708 | } 709 | 710 | static void 711 | gst_ffmpegaudenc_set_property (GObject * object, 712 | guint prop_id, const GValue * value, GParamSpec * pspec) 713 | { 714 | GstFFMpegAudEnc *ffmpegaudenc; 715 | 716 | ffmpegaudenc = (GstFFMpegAudEnc *) (object); 717 | 718 | if (ffmpegaudenc->opened) { 719 | GST_WARNING_OBJECT (ffmpegaudenc, 720 | "Can't change properties once encoder is setup !"); 721 | return; 722 | } 723 | 724 | switch (prop_id) { 725 | default: 726 | if (!gst_ffmpeg_cfg_set_property (ffmpegaudenc->refcontext, value, pspec)) 727 | G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); 728 | break; 729 | } 730 | } 731 | 732 | static void 733 | gst_ffmpegaudenc_get_property (GObject * object, 734 | guint prop_id, GValue * value, GParamSpec * pspec) 735 | { 736 | GstFFMpegAudEnc *ffmpegaudenc; 737 | 738 | ffmpegaudenc = (GstFFMpegAudEnc *) (object); 739 | 740 | switch (prop_id) { 741 | default: 742 | if (!gst_ffmpeg_cfg_get_property (ffmpegaudenc->refcontext, value, pspec)) 743 | G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); 744 | break; 745 | } 746 | } 747 | 748 | gboolean 749 | gst_ffmpegaudenc_register (GstPlugin * plugin) 750 | { 751 | GTypeInfo typeinfo = { 752 | sizeof (GstFFMpegAudEncClass), 753 | (GBaseInitFunc) gst_ffmpegaudenc_base_init, 754 | NULL, 755 | (GClassInitFunc) gst_ffmpegaudenc_class_init, 756 | NULL, 757 | NULL, 758 | sizeof (GstFFMpegAudEnc), 759 | 0, 760 | (GInstanceInitFunc) gst_ffmpegaudenc_init, 761 | }; 762 | GType type; 763 | AVCodec *in_plugin; 764 | void *i = 0; 765 | 766 | 767 | GST_LOG ("Registering encoders"); 768 | 769 | while ((in_plugin = (AVCodec *) av_codec_iterate (&i))) { 770 | gchar *type_name; 771 | guint rank; 772 | 773 | /* Skip non-AV codecs */ 774 | if (in_plugin->type != AVMEDIA_TYPE_AUDIO) 775 | continue; 776 | 777 | /* no quasi codecs, please */ 778 | if (in_plugin->id == AV_CODEC_ID_PCM_S16LE_PLANAR || 779 | (in_plugin->id >= AV_CODEC_ID_PCM_S16LE && 780 | in_plugin->id <= AV_CODEC_ID_PCM_BLURAY) || 781 | (in_plugin->id >= AV_CODEC_ID_PCM_S8_PLANAR && 782 | in_plugin->id <= AV_CODEC_ID_PCM_F24LE)) { 783 | continue; 784 | } 785 | 786 | /* No encoders depending on external libraries (we don't build them, but 787 | * people who build against an external ffmpeg might have them. 788 | * We have native gstreamer plugins for all of those libraries anyway. */ 789 | if (!strncmp (in_plugin->name, "lib", 3)) { 790 | GST_DEBUG 791 | ("Not using external library encoder %s. Use the gstreamer-native ones instead.", 792 | in_plugin->name); 793 | continue; 794 | } 795 | 796 | /* only encoders */ 797 | if (!av_codec_is_encoder (in_plugin)) { 798 | continue; 799 | } 800 | 801 | /* FIXME : We should have a method to know cheaply whether we have a mapping 802 | * for the given plugin or not */ 803 | 804 | GST_DEBUG ("Trying plugin %s [%s]", in_plugin->name, in_plugin->long_name); 805 | 806 | /* no codecs for which we're GUARANTEED to have better alternatives */ 807 | if (!strcmp (in_plugin->name, "vorbis") 808 | || !strcmp (in_plugin->name, "flac")) { 809 | GST_LOG ("Ignoring encoder %s", in_plugin->name); 810 | continue; 811 | } 812 | 813 | /* construct the type */ 814 | type_name = g_strdup_printf ("avenc_%s", in_plugin->name); 815 | 816 | type = g_type_from_name (type_name); 817 | 818 | if (!type) { 819 | 820 | /* create the glib type now */ 821 | type = 822 | g_type_register_static (GST_TYPE_AUDIO_ENCODER, type_name, &typeinfo, 823 | 0); 824 | g_type_set_qdata (type, GST_FFENC_PARAMS_QDATA, (gpointer) in_plugin); 825 | 826 | { 827 | static const GInterfaceInfo preset_info = { 828 | NULL, 829 | NULL, 830 | NULL 831 | }; 832 | g_type_add_interface_static (type, GST_TYPE_PRESET, &preset_info); 833 | } 834 | } 835 | 836 | switch (in_plugin->id) { 837 | /* avenc_aac: see https://bugzilla.gnome.org/show_bug.cgi?id=691617 */ 838 | case AV_CODEC_ID_AAC: 839 | rank = GST_RANK_NONE; 840 | break; 841 | default: 842 | rank = GST_RANK_SECONDARY; 843 | break; 844 | } 845 | 846 | if (!gst_element_register (plugin, type_name, rank, type)) { 847 | g_free (type_name); 848 | return FALSE; 849 | } 850 | 851 | g_free (type_name); 852 | } 853 | 854 | GST_LOG ("Finished registering encoders"); 855 | 856 | return TRUE; 857 | } 858 | -------------------------------------------------------------------------------- /ext/libav/gstavaudenc.h: -------------------------------------------------------------------------------- 1 | /* GStreamer 2 | * Copyright (C) <1999> Erik Walthinsen 3 | * 4 | * This library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Library General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2 of the License, or (at your option) any later version. 8 | * 9 | * This library is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Library General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Library General Public 15 | * License along with this library; if not, write to the 16 | * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, 17 | * Boston, MA 02110-1301, USA. 18 | */ 19 | 20 | /* First, include the header file for the plugin, to bring in the 21 | * object definition and other useful things. 22 | */ 23 | 24 | #ifndef __GST_FFMPEGAUDENC_H__ 25 | #define __GST_FFMPEGAUDENC_H__ 26 | 27 | #include 28 | #include 29 | #include 30 | 31 | G_BEGIN_DECLS 32 | 33 | typedef struct _GstFFMpegAudEnc GstFFMpegAudEnc; 34 | 35 | struct _GstFFMpegAudEnc 36 | { 37 | GstAudioEncoder parent; 38 | 39 | AVCodecContext *context; 40 | AVCodecContext *refcontext; 41 | gboolean opened; 42 | gboolean need_reopen; 43 | 44 | AVFrame *frame; 45 | 46 | GstAudioChannelPosition ffmpeg_layout[64]; 47 | gboolean needs_reorder; 48 | }; 49 | 50 | typedef struct _GstFFMpegAudEncClass GstFFMpegAudEncClass; 51 | 52 | struct _GstFFMpegAudEncClass 53 | { 54 | GstAudioEncoderClass parent_class; 55 | 56 | AVCodec *in_plugin; 57 | GstPadTemplate *srctempl, *sinktempl; 58 | }; 59 | 60 | #define GST_TYPE_FFMPEGAUDENC \ 61 | (gst_ffmpegaudenc_get_type()) 62 | #define GST_FFMPEGAUDENC(obj) \ 63 | (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_FFMPEGAUDENC,GstFFMpegAudEnc)) 64 | #define GST_FFMPEGAUDENC_CLASS(klass) \ 65 | (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_FFMPEGAUDENC,GstFFMpegAudEncClass)) 66 | #define GST_IS_FFMPEGAUDENC(obj) \ 67 | (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_FFMPEGAUDENC)) 68 | #define GST_IS_FFMPEGAUDENC_CLASS(klass) \ 69 | (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_FFMPEGAUDENC)) 70 | 71 | G_END_DECLS 72 | 73 | #endif /* __GST_FFMPEGAUDENC_H__ */ 74 | -------------------------------------------------------------------------------- /ext/libav/gstavcfg.c: -------------------------------------------------------------------------------- 1 | /* GStreamer 2 | * 3 | * FFMpeg Configuration 4 | * 5 | * Copyright (C) <2006> Mark Nauwelaerts 6 | * 7 | * This library is free software; you can redistribute it and/or 8 | * modify it under the terms of the GNU Library General Public 9 | * License as published by the Free Software Foundation; either 10 | * version 2 of the License, or (at your option) any later version. 11 | * 12 | * This library is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * Library General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU Library General Public 18 | * License along with this library; if not, write to the 19 | * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, 20 | * Boston, MA 02110-1301, USA. 21 | */ 22 | 23 | 24 | #ifdef HAVE_CONFIG_H 25 | #include "config.h" 26 | #endif 27 | 28 | #include "gstav.h" 29 | #include "gstavvidenc.h" 30 | #include "gstavcfg.h" 31 | 32 | #include 33 | #include 34 | 35 | static GQuark avoption_quark; 36 | static GHashTable *generic_overrides = NULL; 37 | 38 | static void 39 | make_generic_overrides (void) 40 | { 41 | g_assert (!generic_overrides); 42 | generic_overrides = g_hash_table_new_full (g_str_hash, g_str_equal, 43 | g_free, (GDestroyNotify) gst_structure_free); 44 | 45 | g_hash_table_insert (generic_overrides, g_strdup ("b"), 46 | gst_structure_new_empty ("bitrate")); 47 | g_hash_table_insert (generic_overrides, g_strdup ("ab"), 48 | gst_structure_new_empty ("bitrate")); 49 | g_hash_table_insert (generic_overrides, g_strdup ("g"), 50 | gst_structure_new_empty ("gop-size")); 51 | g_hash_table_insert (generic_overrides, g_strdup ("bt"), 52 | gst_structure_new_empty ("bitrate-tolerance")); 53 | g_hash_table_insert (generic_overrides, g_strdup ("bf"), 54 | gst_structure_new_empty ("max-bframes")); 55 | 56 | /* Those are exposed through caps */ 57 | g_hash_table_insert (generic_overrides, g_strdup ("profile"), 58 | gst_structure_new ("profile", "skip", G_TYPE_BOOLEAN, TRUE, NULL)); 59 | g_hash_table_insert (generic_overrides, g_strdup ("level"), 60 | gst_structure_new ("level", "skip", G_TYPE_BOOLEAN, TRUE, NULL)); 61 | g_hash_table_insert (generic_overrides, g_strdup ("color_primaries"), 62 | gst_structure_new ("color_primaries", "skip", G_TYPE_BOOLEAN, TRUE, 63 | NULL)); 64 | g_hash_table_insert (generic_overrides, g_strdup ("color_trc"), 65 | gst_structure_new ("color_trc", "skip", G_TYPE_BOOLEAN, TRUE, NULL)); 66 | g_hash_table_insert (generic_overrides, g_strdup ("colorspace"), 67 | gst_structure_new ("colorspace", "skip", G_TYPE_BOOLEAN, TRUE, NULL)); 68 | g_hash_table_insert (generic_overrides, g_strdup ("color_range"), 69 | gst_structure_new ("color_range", "skip", G_TYPE_BOOLEAN, TRUE, NULL)); 70 | } 71 | 72 | void 73 | gst_ffmpeg_cfg_init (void) 74 | { 75 | avoption_quark = g_quark_from_static_string ("ffmpeg-cfg-param-spec-data"); 76 | make_generic_overrides (); 77 | } 78 | 79 | static gint 80 | cmp_enum_value (GEnumValue * val1, GEnumValue * val2) 81 | { 82 | return val1->value - val2->value; 83 | } 84 | 85 | static GType 86 | register_enum (const AVClass ** obj, const AVOption * top_opt) 87 | { 88 | const AVOption *opt = NULL; 89 | GType res = 0; 90 | GArray *values = g_array_new (TRUE, TRUE, sizeof (GEnumValue)); 91 | gchar *lower_obj_name = g_ascii_strdown ((*obj)->class_name, -1); 92 | gchar *enum_name = g_strdup_printf ("%s-%s", lower_obj_name, top_opt->unit); 93 | gboolean none_default = TRUE; 94 | 95 | g_strcanon (enum_name, G_CSET_a_2_z G_CSET_DIGITS, '-'); 96 | 97 | if ((res = g_type_from_name (enum_name))) 98 | goto done; 99 | 100 | while ((opt = av_opt_next (obj, opt))) { 101 | if (opt->type == AV_OPT_TYPE_CONST && !g_strcmp0 (top_opt->unit, opt->unit)) { 102 | GEnumValue val; 103 | 104 | val.value = opt->default_val.i64; 105 | val.value_name = g_strdup (opt->help ? opt->help : opt->name); 106 | val.value_nick = g_strdup (opt->name); 107 | 108 | if (opt->default_val.i64 == top_opt->default_val.i64) 109 | none_default = FALSE; 110 | 111 | g_array_append_val (values, val); 112 | } 113 | } 114 | 115 | if (values->len) { 116 | guint i = 0; 117 | gint cur_val; 118 | gboolean cur_val_set = FALSE; 119 | 120 | /* Sometimes ffmpeg sets a default value but no named constants with 121 | * this value, we assume this means "unspecified" and add our own 122 | */ 123 | if (none_default) { 124 | GEnumValue val; 125 | 126 | val.value = top_opt->default_val.i64; 127 | val.value_name = g_strdup ("Unspecified"); 128 | val.value_nick = g_strdup ("unknown"); 129 | g_array_append_val (values, val); 130 | } 131 | 132 | g_array_sort (values, (GCompareFunc) cmp_enum_value); 133 | 134 | /* Dedup, easy once sorted 135 | * We do this because ffmpeg can expose multiple names for the 136 | * same constant, the way we expose enums makes this too confusing. 137 | */ 138 | while (i < values->len) { 139 | if (cur_val_set) { 140 | if (g_array_index (values, GEnumValue, i).value == cur_val) { 141 | g_array_remove_index (values, i); 142 | } else { 143 | cur_val = g_array_index (values, GEnumValue, i).value; 144 | i++; 145 | } 146 | } else { 147 | cur_val = g_array_index (values, GEnumValue, i).value; 148 | cur_val_set = TRUE; 149 | i++; 150 | } 151 | } 152 | 153 | res = 154 | g_enum_register_static (enum_name, &g_array_index (values, GEnumValue, 155 | 0)); 156 | 157 | gst_type_mark_as_plugin_api (res, 0); 158 | } 159 | 160 | done: 161 | g_free (lower_obj_name); 162 | g_free (enum_name); 163 | return res; 164 | } 165 | 166 | static gint 167 | cmp_flags_value (GEnumValue * val1, GEnumValue * val2) 168 | { 169 | return val1->value - val2->value; 170 | } 171 | 172 | static GType 173 | register_flags (const AVClass ** obj, const AVOption * top_opt) 174 | { 175 | const AVOption *opt = NULL; 176 | GType res = 0; 177 | GArray *values = g_array_new (TRUE, TRUE, sizeof (GEnumValue)); 178 | gchar *lower_obj_name = g_ascii_strdown ((*obj)->class_name, -1); 179 | gchar *flags_name = g_strdup_printf ("%s-%s", lower_obj_name, top_opt->unit); 180 | 181 | g_strcanon (flags_name, G_CSET_a_2_z G_CSET_DIGITS, '-'); 182 | 183 | if ((res = g_type_from_name (flags_name))) 184 | goto done; 185 | 186 | while ((opt = av_opt_next (obj, opt))) { 187 | if (opt->type == AV_OPT_TYPE_CONST && !g_strcmp0 (top_opt->unit, opt->unit)) { 188 | GFlagsValue val; 189 | 190 | /* We expose pass manually, hardcoding this isn't very nice, but 191 | * I don't expect we want to do that sort of things often enough 192 | * to warrant a general mechanism 193 | */ 194 | if (!g_strcmp0 (top_opt->name, "flags")) { 195 | if (opt->default_val.i64 == AV_CODEC_FLAG_QSCALE || 196 | opt->default_val.i64 == AV_CODEC_FLAG_PASS1 || 197 | opt->default_val.i64 == AV_CODEC_FLAG_PASS2) { 198 | continue; 199 | } 200 | } 201 | 202 | val.value = opt->default_val.i64; 203 | val.value_name = g_strdup (opt->help ? opt->help : opt->name); 204 | val.value_nick = g_strdup (opt->name); 205 | 206 | g_array_append_val (values, val); 207 | } 208 | } 209 | 210 | if (values->len) { 211 | g_array_sort (values, (GCompareFunc) cmp_flags_value); 212 | 213 | res = 214 | g_flags_register_static (flags_name, &g_array_index (values, 215 | GFlagsValue, 0)); 216 | 217 | gst_type_mark_as_plugin_api (res, 0); 218 | } 219 | 220 | done: 221 | g_free (lower_obj_name); 222 | g_free (flags_name); 223 | return res; 224 | } 225 | 226 | static guint 227 | install_opts (GObjectClass * gobject_class, const AVClass ** obj, guint prop_id, 228 | gint flags, const gchar * extra_help, GHashTable * overrides) 229 | { 230 | const AVOption *opt = NULL; 231 | 232 | while ((opt = av_opt_next (obj, opt))) { 233 | GParamSpec *pspec = NULL; 234 | AVOptionRanges *r; 235 | gdouble min = G_MINDOUBLE; 236 | gdouble max = G_MAXDOUBLE; 237 | gchar *help; 238 | const gchar *name; 239 | 240 | if (overrides && g_hash_table_contains (overrides, opt->name)) { 241 | gboolean skip; 242 | const GstStructure *s = 243 | (GstStructure *) g_hash_table_lookup (overrides, opt->name); 244 | 245 | name = gst_structure_get_name (s); 246 | if (gst_structure_get_boolean (s, "skip", &skip) && skip) { 247 | continue; 248 | } 249 | } else { 250 | name = opt->name; 251 | } 252 | 253 | if ((opt->flags & flags) != flags) 254 | continue; 255 | 256 | if (g_object_class_find_property (gobject_class, name)) 257 | continue; 258 | 259 | if (av_opt_query_ranges (&r, obj, opt->name, AV_OPT_SEARCH_FAKE_OBJ) >= 0) { 260 | if (r->nb_ranges == 1) { 261 | min = r->range[0]->value_min; 262 | max = r->range[0]->value_max; 263 | } 264 | av_opt_freep_ranges (&r); 265 | } 266 | 267 | help = g_strdup_printf ("%s%s", opt->help, extra_help); 268 | 269 | switch (opt->type) { 270 | case AV_OPT_TYPE_INT: 271 | if (opt->unit) { 272 | GType enum_gtype; 273 | enum_gtype = register_enum (obj, opt); 274 | 275 | if (enum_gtype) { 276 | pspec = g_param_spec_enum (name, name, help, 277 | enum_gtype, opt->default_val.i64, G_PARAM_READWRITE); 278 | g_object_class_install_property (gobject_class, prop_id++, pspec); 279 | } else { /* Some options have a unit but no named constants associated */ 280 | pspec = g_param_spec_int (name, name, help, 281 | (gint) min, (gint) max, opt->default_val.i64, 282 | G_PARAM_READWRITE); 283 | g_object_class_install_property (gobject_class, prop_id++, pspec); 284 | } 285 | } else { 286 | pspec = g_param_spec_int (name, name, help, 287 | (gint) min, (gint) max, opt->default_val.i64, G_PARAM_READWRITE); 288 | g_object_class_install_property (gobject_class, prop_id++, pspec); 289 | } 290 | break; 291 | case AV_OPT_TYPE_FLAGS: 292 | if (opt->unit) { 293 | GType flags_gtype; 294 | flags_gtype = register_flags (obj, opt); 295 | 296 | if (flags_gtype) { 297 | pspec = g_param_spec_flags (name, name, help, 298 | flags_gtype, opt->default_val.i64, G_PARAM_READWRITE); 299 | g_object_class_install_property (gobject_class, prop_id++, pspec); 300 | } 301 | } 302 | break; 303 | case AV_OPT_TYPE_DURATION: /* Fall through */ 304 | case AV_OPT_TYPE_INT64: 305 | /* FIXME 2.0: Workaround for worst property related API change. We 306 | * continue using a 32 bit integer for the bitrate property as 307 | * otherwise too much existing code will fail at runtime. 308 | * 309 | * See https://gitlab.freedesktop.org/gstreamer/gst-libav/issues/41#note_142808 */ 310 | if (g_strcmp0 (name, "bitrate") == 0) { 311 | pspec = g_param_spec_int (name, name, help, 312 | (gint) MAX (min, G_MININT), (gint) MIN (max, G_MAXINT), 313 | (gint) opt->default_val.i64, G_PARAM_READWRITE); 314 | } else { 315 | /* ffmpeg expresses all ranges with doubles, this is sad */ 316 | pspec = g_param_spec_int64 (name, name, help, 317 | (min == (gdouble) INT64_MIN ? INT64_MIN : (gint64) min), 318 | (max == (gdouble) INT64_MAX ? INT64_MAX : (gint64) max), 319 | opt->default_val.i64, G_PARAM_READWRITE); 320 | } 321 | g_object_class_install_property (gobject_class, prop_id++, pspec); 322 | break; 323 | case AV_OPT_TYPE_DOUBLE: 324 | pspec = g_param_spec_double (name, name, help, 325 | min, max, opt->default_val.dbl, G_PARAM_READWRITE); 326 | g_object_class_install_property (gobject_class, prop_id++, pspec); 327 | break; 328 | case AV_OPT_TYPE_FLOAT: 329 | pspec = g_param_spec_float (name, name, help, 330 | (gfloat) min, (gfloat) max, (gfloat) opt->default_val.dbl, 331 | G_PARAM_READWRITE); 332 | g_object_class_install_property (gobject_class, prop_id++, pspec); 333 | break; 334 | case AV_OPT_TYPE_STRING: 335 | pspec = g_param_spec_string (name, name, help, 336 | opt->default_val.str, G_PARAM_READWRITE); 337 | g_object_class_install_property (gobject_class, prop_id++, pspec); 338 | break; 339 | case AV_OPT_TYPE_UINT64: 340 | /* ffmpeg expresses all ranges with doubles, this is appalling */ 341 | pspec = g_param_spec_uint64 (name, name, help, 342 | (guint64) (min <= (gdouble) 0 ? 0 : (guint64) min), 343 | (guint64) (max >= 344 | /* Biggest value before UINT64_MAX that can be represented as double */ 345 | (gdouble) 18446744073709550000.0 ? 346 | /* The Double conversion rounds UINT64_MAX to a bigger */ 347 | /* value, so the following smaller limit must be used. */ 348 | G_GUINT64_CONSTANT (18446744073709550000) : (guint64) max), 349 | opt->default_val.i64, G_PARAM_READWRITE); 350 | g_object_class_install_property (gobject_class, prop_id++, pspec); 351 | break; 352 | case AV_OPT_TYPE_BOOL: 353 | pspec = g_param_spec_boolean (name, name, help, 354 | opt->default_val.i64 ? TRUE : FALSE, G_PARAM_READWRITE); 355 | g_object_class_install_property (gobject_class, prop_id++, pspec); 356 | break; 357 | /* TODO: didn't find options for the video encoders with 358 | * the following type, add support if needed */ 359 | case AV_OPT_TYPE_CHANNEL_LAYOUT: 360 | case AV_OPT_TYPE_COLOR: 361 | case AV_OPT_TYPE_VIDEO_RATE: 362 | case AV_OPT_TYPE_SAMPLE_FMT: 363 | case AV_OPT_TYPE_PIXEL_FMT: 364 | case AV_OPT_TYPE_IMAGE_SIZE: 365 | case AV_OPT_TYPE_DICT: 366 | case AV_OPT_TYPE_BINARY: 367 | case AV_OPT_TYPE_RATIONAL: 368 | default: 369 | break; 370 | } 371 | 372 | g_free (help); 373 | 374 | if (pspec) { 375 | g_param_spec_set_qdata (pspec, avoption_quark, (gpointer) opt); 376 | } 377 | } 378 | 379 | return prop_id; 380 | } 381 | 382 | void 383 | gst_ffmpeg_cfg_install_properties (GObjectClass * klass, AVCodec * in_plugin, 384 | guint base, gint flags) 385 | { 386 | gint prop_id; 387 | AVCodecContext *ctx; 388 | 389 | prop_id = base; 390 | g_return_if_fail (base > 0); 391 | 392 | ctx = avcodec_alloc_context3 (in_plugin); 393 | if (!ctx) 394 | g_warning ("could not get context"); 395 | 396 | prop_id = 397 | install_opts ((GObjectClass *) klass, &in_plugin->priv_class, prop_id, 0, 398 | " (Private codec option)", NULL); 399 | prop_id = 400 | install_opts ((GObjectClass *) klass, &ctx->av_class, prop_id, flags, 401 | " (Generic codec option, might have no effect)", generic_overrides); 402 | 403 | if (ctx) { 404 | gst_ffmpeg_avcodec_close (ctx); 405 | av_free (ctx); 406 | } 407 | } 408 | 409 | static gint 410 | set_option_value (AVCodecContext * ctx, GParamSpec * pspec, 411 | const GValue * value, const AVOption * opt) 412 | { 413 | int res = -1; 414 | 415 | switch (G_PARAM_SPEC_VALUE_TYPE (pspec)) { 416 | case G_TYPE_INT: 417 | res = av_opt_set_int (ctx, opt->name, 418 | g_value_get_int (value), AV_OPT_SEARCH_CHILDREN); 419 | break; 420 | case G_TYPE_INT64: 421 | res = av_opt_set_int (ctx, opt->name, 422 | g_value_get_int64 (value), AV_OPT_SEARCH_CHILDREN); 423 | break; 424 | case G_TYPE_UINT64: 425 | res = av_opt_set_int (ctx, opt->name, 426 | g_value_get_uint64 (value), AV_OPT_SEARCH_CHILDREN); 427 | break; 428 | case G_TYPE_DOUBLE: 429 | res = av_opt_set_double (ctx, opt->name, 430 | g_value_get_double (value), AV_OPT_SEARCH_CHILDREN); 431 | break; 432 | case G_TYPE_FLOAT: 433 | res = av_opt_set_double (ctx, opt->name, 434 | g_value_get_float (value), AV_OPT_SEARCH_CHILDREN); 435 | break; 436 | case G_TYPE_STRING: 437 | res = av_opt_set (ctx, opt->name, 438 | g_value_get_string (value), AV_OPT_SEARCH_CHILDREN); 439 | /* Some code in FFmpeg returns ENOMEM if the string is NULL: 440 | * *dst = av_strdup(val); 441 | * return *dst ? 0 : AVERROR(ENOMEM); 442 | * That makes little sense, let's ignore that 443 | */ 444 | if (!g_value_get_string (value)) 445 | res = 0; 446 | break; 447 | case G_TYPE_BOOLEAN: 448 | res = av_opt_set_int (ctx, opt->name, 449 | g_value_get_boolean (value), AV_OPT_SEARCH_CHILDREN); 450 | break; 451 | default: 452 | if (G_IS_PARAM_SPEC_ENUM (pspec)) { 453 | res = av_opt_set_int (ctx, opt->name, 454 | g_value_get_enum (value), AV_OPT_SEARCH_CHILDREN); 455 | } else if (G_IS_PARAM_SPEC_FLAGS (pspec)) { 456 | res = av_opt_set_int (ctx, opt->name, 457 | g_value_get_flags (value), AV_OPT_SEARCH_CHILDREN); 458 | } else { /* oops, bit lazy we don't cover this case yet */ 459 | g_critical ("%s does not yet support type %s", GST_FUNCTION, 460 | g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec))); 461 | } 462 | } 463 | 464 | return res; 465 | } 466 | 467 | gboolean 468 | gst_ffmpeg_cfg_set_property (AVCodecContext * refcontext, const GValue * value, 469 | GParamSpec * pspec) 470 | { 471 | const AVOption *opt; 472 | 473 | opt = g_param_spec_get_qdata (pspec, avoption_quark); 474 | 475 | if (!opt) 476 | return FALSE; 477 | 478 | return set_option_value (refcontext, pspec, value, opt) >= 0; 479 | } 480 | 481 | gboolean 482 | gst_ffmpeg_cfg_get_property (AVCodecContext * refcontext, GValue * value, 483 | GParamSpec * pspec) 484 | { 485 | const AVOption *opt; 486 | int res = -1; 487 | 488 | opt = g_param_spec_get_qdata (pspec, avoption_quark); 489 | 490 | if (!opt) 491 | return FALSE; 492 | 493 | switch (G_PARAM_SPEC_VALUE_TYPE (pspec)) { 494 | case G_TYPE_INT: 495 | { 496 | int64_t val; 497 | if ((res = av_opt_get_int (refcontext, opt->name, 498 | AV_OPT_SEARCH_CHILDREN, &val) >= 0)) 499 | g_value_set_int (value, val); 500 | break; 501 | } 502 | case G_TYPE_INT64: 503 | { 504 | int64_t val; 505 | if ((res = av_opt_get_int (refcontext, opt->name, 506 | AV_OPT_SEARCH_CHILDREN, &val) >= 0)) 507 | g_value_set_int64 (value, val); 508 | break; 509 | } 510 | case G_TYPE_UINT64: 511 | { 512 | int64_t val; 513 | if ((res = av_opt_get_int (refcontext, opt->name, 514 | AV_OPT_SEARCH_CHILDREN, &val) >= 0)) 515 | g_value_set_uint64 (value, val); 516 | break; 517 | } 518 | case G_TYPE_DOUBLE: 519 | { 520 | gdouble val; 521 | if ((res = av_opt_get_double (refcontext, opt->name, 522 | AV_OPT_SEARCH_CHILDREN, &val) >= 0)) 523 | g_value_set_double (value, val); 524 | break; 525 | } 526 | case G_TYPE_FLOAT: 527 | { 528 | gdouble val; 529 | if ((res = av_opt_get_double (refcontext, opt->name, 530 | AV_OPT_SEARCH_CHILDREN, &val) >= 0)) 531 | g_value_set_float (value, (gfloat) val); 532 | break; 533 | } 534 | case G_TYPE_STRING: 535 | { 536 | uint8_t *val; 537 | if ((res = av_opt_get (refcontext, opt->name, 538 | AV_OPT_SEARCH_CHILDREN | AV_OPT_ALLOW_NULL, &val) >= 0)) { 539 | g_value_set_string (value, (gchar *) val); 540 | } 541 | break; 542 | } 543 | case G_TYPE_BOOLEAN: 544 | { 545 | int64_t val; 546 | if ((res = av_opt_get_int (refcontext, opt->name, 547 | AV_OPT_SEARCH_CHILDREN, &val) >= 0)) 548 | g_value_set_boolean (value, val ? TRUE : FALSE); 549 | break; 550 | } 551 | default: 552 | if (G_IS_PARAM_SPEC_ENUM (pspec)) { 553 | int64_t val; 554 | 555 | if ((res = av_opt_get_int (refcontext, opt->name, 556 | AV_OPT_SEARCH_CHILDREN, &val) >= 0)) 557 | g_value_set_enum (value, val); 558 | } else if (G_IS_PARAM_SPEC_FLAGS (pspec)) { 559 | int64_t val; 560 | 561 | if ((res = av_opt_get_int (refcontext, opt->name, 562 | AV_OPT_SEARCH_CHILDREN, &val) >= 0)) 563 | g_value_set_flags (value, val); 564 | } else { /* oops, bit lazy we don't cover this case yet */ 565 | g_critical ("%s does not yet support type %s", GST_FUNCTION, 566 | g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec))); 567 | } 568 | } 569 | 570 | return res >= 0; 571 | } 572 | 573 | void 574 | gst_ffmpeg_cfg_fill_context (GObject * object, AVCodecContext * context) 575 | { 576 | GParamSpec **pspecs; 577 | guint num_props, i; 578 | 579 | pspecs = g_object_class_list_properties (G_OBJECT_GET_CLASS (object), 580 | &num_props); 581 | 582 | for (i = 0; i < num_props; ++i) { 583 | GParamSpec *pspec = pspecs[i]; 584 | const AVOption *opt; 585 | GValue value = G_VALUE_INIT; 586 | 587 | opt = g_param_spec_get_qdata (pspec, avoption_quark); 588 | 589 | if (!opt) 590 | continue; 591 | 592 | g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec)); 593 | g_object_get_property (object, pspec->name, &value); 594 | set_option_value (context, pspec, &value, opt); 595 | g_value_unset (&value); 596 | } 597 | g_free (pspecs); 598 | } 599 | 600 | void 601 | gst_ffmpeg_cfg_finalize (void) 602 | { 603 | GST_ERROR ("Finalizing"); 604 | g_assert (generic_overrides); 605 | g_hash_table_unref (generic_overrides); 606 | } 607 | -------------------------------------------------------------------------------- /ext/libav/gstavcfg.h: -------------------------------------------------------------------------------- 1 | /* GStreamer 2 | * Copyright (C) <2006> Mark Nauwelaerts 3 | * 4 | * This library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Library General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2 of the License, or (at your option) any later version. 8 | * 9 | * This library is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Library General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Library General Public 15 | * License along with this library; if not, write to the 16 | * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, 17 | * Boston, MA 02110-1301, USA. 18 | */ 19 | 20 | 21 | #ifndef __GST_FFMPEGCFG_H__ 22 | #define __GST_FFMPEGCFG_H__ 23 | 24 | #include 25 | #include 26 | 27 | G_BEGIN_DECLS 28 | 29 | void gst_ffmpeg_cfg_init (void); 30 | 31 | void gst_ffmpeg_cfg_install_properties (GObjectClass * klass, AVCodec *in_plugin, guint base, gint flags); 32 | 33 | gboolean gst_ffmpeg_cfg_set_property (AVCodecContext *refcontext, 34 | const GValue * value, GParamSpec * pspec); 35 | 36 | gboolean gst_ffmpeg_cfg_get_property (AVCodecContext *refcontext, 37 | GValue * value, GParamSpec * pspec); 38 | 39 | void gst_ffmpeg_cfg_fill_context (GObject *object, AVCodecContext * context); 40 | void gst_ffmpeg_cfg_finalize (void); 41 | 42 | G_END_DECLS 43 | 44 | 45 | #endif /* __GST_FFMPEGCFG_H__ */ 46 | -------------------------------------------------------------------------------- /ext/libav/gstavcodecmap.h: -------------------------------------------------------------------------------- 1 | /* GStreamer 2 | * Copyright (C) <1999> Erik Walthinsen 3 | * 4 | * This library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Library General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2 of the License, or (at your option) any later version. 8 | * 9 | * This library is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Library General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Library General Public 15 | * License along with this library; if not, write to the 16 | * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, 17 | * Boston, MA 02110-1301, USA. 18 | */ 19 | 20 | #ifndef __GST_FFMPEG_CODECMAP_H__ 21 | #define __GST_FFMPEG_CODECMAP_H__ 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | /* 30 | * _codecid_is_image() returns TRUE for image formats 31 | */ 32 | gboolean 33 | gst_ffmpeg_codecid_is_image (enum AVCodecID codec_id); 34 | 35 | /* 36 | * _codecid_to_caps () gets the GstCaps that belongs to 37 | * a certain CodecID for a pad with compressed data. 38 | */ 39 | 40 | GstCaps * 41 | gst_ffmpeg_codecid_to_caps (enum AVCodecID codec_id, 42 | AVCodecContext *context, 43 | gboolean encode); 44 | 45 | /* 46 | * _codectype_to_caps () gets the GstCaps that belongs to 47 | * a certain AVMediaType for a pad with uncompressed data. 48 | */ 49 | 50 | GstCaps * 51 | gst_ffmpeg_codectype_to_audio_caps (AVCodecContext *context, 52 | enum AVCodecID codec_id, 53 | gboolean encode, 54 | AVCodec *codec); 55 | GstCaps * 56 | gst_ffmpeg_codectype_to_video_caps (AVCodecContext *context, 57 | enum AVCodecID codec_id, 58 | gboolean encode, 59 | AVCodec *codec); 60 | 61 | /* 62 | * caps_to_codecid () transforms a GstCaps that belongs to 63 | * a pad for compressed data to (optionally) a filled-in 64 | * context and a codecID. 65 | */ 66 | 67 | enum AVCodecID 68 | gst_ffmpeg_caps_to_codecid (const GstCaps *caps, 69 | AVCodecContext *context); 70 | 71 | /* 72 | * caps_with_codecid () transforms a GstCaps for a known codec 73 | * ID into a filled-in context. 74 | */ 75 | 76 | void 77 | gst_ffmpeg_caps_with_codecid (enum AVCodecID codec_id, 78 | enum AVMediaType codec_type, 79 | const GstCaps *caps, 80 | AVCodecContext *context); 81 | 82 | /* 83 | * caps_with_codectype () transforms a GstCaps that belongs to 84 | * a pad for uncompressed data to a filled-in context. 85 | */ 86 | 87 | void 88 | gst_ffmpeg_caps_with_codectype (enum AVMediaType type, 89 | const GstCaps *caps, 90 | AVCodecContext *context); 91 | 92 | void 93 | gst_ffmpeg_videoinfo_to_context (GstVideoInfo *info, 94 | AVCodecContext *context); 95 | 96 | void 97 | gst_ffmpeg_audioinfo_to_context (GstAudioInfo *info, 98 | AVCodecContext *context); 99 | 100 | GstVideoFormat gst_ffmpeg_pixfmt_to_videoformat (enum AVPixelFormat pixfmt); 101 | enum AVPixelFormat gst_ffmpeg_videoformat_to_pixfmt (GstVideoFormat format); 102 | 103 | GstAudioFormat gst_ffmpeg_smpfmt_to_audioformat (enum AVSampleFormat sample_fmt, 104 | GstAudioLayout * layout); 105 | 106 | /* 107 | * _formatid_to_caps () is meant for muxers/demuxers, it 108 | * transforms a name (ffmpeg way of ID'ing these, why don't 109 | * they have unique numerical IDs?) to the corresponding 110 | * caps belonging to that mux-format 111 | */ 112 | 113 | GstCaps * 114 | gst_ffmpeg_formatid_to_caps (const gchar *format_name); 115 | 116 | /* 117 | * _formatid_get_codecids () can be used to get the codecIDs 118 | * (AV_CODEC_ID_NONE-terminated list) that fit that specific 119 | * output format. 120 | */ 121 | 122 | gboolean 123 | gst_ffmpeg_formatid_get_codecids (const gchar *format_name, 124 | enum AVCodecID ** video_codec_list, 125 | enum AVCodecID ** audio_codec_list, 126 | AVOutputFormat * plugin); 127 | 128 | 129 | gboolean 130 | gst_ffmpeg_channel_layout_to_gst (guint64 channel_layout, gint channels, 131 | GstAudioChannelPosition * pos); 132 | 133 | #endif /* __GST_FFMPEG_CODECMAP_H__ */ 134 | -------------------------------------------------------------------------------- /ext/libav/gstavdeinterlace.c: -------------------------------------------------------------------------------- 1 | /* GStreamer 2 | * Copyright (C) <1999> Erik Walthinsen 3 | * This file: 4 | * Copyright (C) 2005 Luca Ognibene 5 | * Copyright (C) 2006 Martin Zlomek 6 | * 7 | * This library is free software; you can redistribute it and/or 8 | * modify it under the terms of the GNU Library General Public 9 | * License as published by the Free Software Foundation; either 10 | * version 2 of the License, or (at your option) any later version. 11 | * 12 | * This library is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * Library General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU Library General Public 18 | * License along with this library; if not, write to the 19 | * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, 20 | * Boston, MA 02110-1301, USA. 21 | */ 22 | 23 | #ifdef HAVE_CONFIG_H 24 | # include "config.h" 25 | #endif 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | #include 34 | #include 35 | 36 | #include "gstav.h" 37 | #include "gstavcodecmap.h" 38 | #include "gstavutils.h" 39 | 40 | 41 | /* Properties */ 42 | 43 | #define DEFAULT_MODE GST_FFMPEGDEINTERLACE_MODE_AUTO 44 | 45 | enum 46 | { 47 | PROP_0, 48 | PROP_MODE, 49 | PROP_LAST 50 | }; 51 | 52 | typedef enum 53 | { 54 | GST_FFMPEGDEINTERLACE_MODE_AUTO, 55 | GST_FFMPEGDEINTERLACE_MODE_INTERLACED, 56 | GST_FFMPEGDEINTERLACE_MODE_DISABLED 57 | } GstFFMpegDeinterlaceMode; 58 | 59 | #define GST_TYPE_FFMPEGDEINTERLACE_MODES (gst_ffmpegdeinterlace_modes_get_type ()) 60 | static GType 61 | gst_ffmpegdeinterlace_modes_get_type (void) 62 | { 63 | static GType deinterlace_modes_type = 0; 64 | 65 | static const GEnumValue modes_types[] = { 66 | {GST_FFMPEGDEINTERLACE_MODE_AUTO, "Auto detection", "auto"}, 67 | {GST_FFMPEGDEINTERLACE_MODE_INTERLACED, "Force deinterlacing", 68 | "interlaced"}, 69 | {GST_FFMPEGDEINTERLACE_MODE_DISABLED, "Run in passthrough mode", 70 | "disabled"}, 71 | {0, NULL, NULL}, 72 | }; 73 | 74 | if (!deinterlace_modes_type) { 75 | deinterlace_modes_type = 76 | g_enum_register_static ("GstLibAVDeinterlaceModes", modes_types); 77 | } 78 | return deinterlace_modes_type; 79 | } 80 | 81 | typedef struct _GstFFMpegDeinterlace 82 | { 83 | GstElement element; 84 | 85 | GstPad *sinkpad, *srcpad; 86 | 87 | gint width, height; 88 | gint to_size; 89 | 90 | GstFFMpegDeinterlaceMode mode; 91 | 92 | gboolean interlaced; /* is input interlaced? */ 93 | gboolean passthrough; 94 | 95 | gboolean reconfigure; 96 | GstFFMpegDeinterlaceMode new_mode; 97 | 98 | enum AVPixelFormat pixfmt; 99 | AVFrame from_frame, to_frame; 100 | 101 | AVFilterContext *buffersink_ctx; 102 | AVFilterContext *buffersrc_ctx; 103 | AVFilterGraph *filter_graph; 104 | AVFrame *filter_frame; 105 | int last_width, last_height; 106 | enum AVPixelFormat last_pixfmt; 107 | 108 | } GstFFMpegDeinterlace; 109 | 110 | typedef struct _GstFFMpegDeinterlaceClass 111 | { 112 | GstElementClass parent_class; 113 | } GstFFMpegDeinterlaceClass; 114 | 115 | #define GST_TYPE_FFMPEGDEINTERLACE \ 116 | (gst_ffmpegdeinterlace_get_type()) 117 | #define GST_FFMPEGDEINTERLACE(obj) \ 118 | (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_FFMPEGDEINTERLACE,GstFFMpegDeinterlace)) 119 | #define GST_FFMPEGDEINTERLACE_CLASS(klass) \ 120 | (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_FFMPEGDEINTERLACE,GstFFMpegDeinterlace)) 121 | #define GST_IS_FFMPEGDEINTERLACE(obj) \ 122 | (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_FFMPEGDEINTERLACE)) 123 | #define GST_IS_FFMPEGDEINTERLACE_CLASS(klass) \ 124 | (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_FFMPEGDEINTERLACE)) 125 | 126 | GType gst_ffmpegdeinterlace_get_type (void); 127 | 128 | static void gst_ffmpegdeinterlace_set_property (GObject * self, guint prop_id, 129 | const GValue * value, GParamSpec * pspec); 130 | static void gst_ffmpegdeinterlace_get_property (GObject * self, guint prop_id, 131 | GValue * value, GParamSpec * pspec); 132 | 133 | static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src", 134 | GST_PAD_SRC, 135 | GST_PAD_ALWAYS, 136 | GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("I420")) 137 | ); 138 | 139 | static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink", 140 | GST_PAD_SINK, 141 | GST_PAD_ALWAYS, 142 | GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("I420")) 143 | ); 144 | 145 | G_DEFINE_TYPE (GstFFMpegDeinterlace, gst_ffmpegdeinterlace, GST_TYPE_ELEMENT); 146 | 147 | static GstFlowReturn gst_ffmpegdeinterlace_chain (GstPad * pad, 148 | GstObject * parent, GstBuffer * inbuf); 149 | 150 | static void gst_ffmpegdeinterlace_dispose (GObject * obj); 151 | 152 | static void 153 | gst_ffmpegdeinterlace_class_init (GstFFMpegDeinterlaceClass * klass) 154 | { 155 | GObjectClass *gobject_class = (GObjectClass *) klass; 156 | GstElementClass *element_class = GST_ELEMENT_CLASS (klass); 157 | 158 | gobject_class->set_property = gst_ffmpegdeinterlace_set_property; 159 | gobject_class->get_property = gst_ffmpegdeinterlace_get_property; 160 | 161 | /** 162 | * GstFFMpegDeinterlace:mode 163 | * 164 | * This selects whether the deinterlacing methods should 165 | * always be applied or if they should only be applied 166 | * on content that has the "interlaced" flag on the caps. 167 | * 168 | * Since: 0.10.13 169 | */ 170 | g_object_class_install_property (gobject_class, PROP_MODE, 171 | g_param_spec_enum ("mode", "Mode", "Deinterlace Mode", 172 | GST_TYPE_FFMPEGDEINTERLACE_MODES, 173 | DEFAULT_MODE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS) 174 | ); 175 | 176 | gst_element_class_add_static_pad_template (element_class, &src_factory); 177 | gst_element_class_add_static_pad_template (element_class, &sink_factory); 178 | 179 | gst_element_class_set_static_metadata (element_class, 180 | "libav Deinterlace element", "Filter/Effect/Video/Deinterlace", 181 | "Deinterlace video", "Luca Ognibene "); 182 | 183 | gobject_class->dispose = gst_ffmpegdeinterlace_dispose; 184 | 185 | gst_type_mark_as_plugin_api (GST_TYPE_FFMPEGDEINTERLACE_MODES, 0); 186 | } 187 | 188 | static void 189 | gst_ffmpegdeinterlace_update_passthrough (GstFFMpegDeinterlace * deinterlace) 190 | { 191 | deinterlace->passthrough = 192 | (deinterlace->mode == GST_FFMPEGDEINTERLACE_MODE_DISABLED 193 | || (!deinterlace->interlaced 194 | && deinterlace->mode != GST_FFMPEGDEINTERLACE_MODE_INTERLACED)); 195 | GST_DEBUG_OBJECT (deinterlace, "Passthrough: %d", deinterlace->passthrough); 196 | } 197 | 198 | static gboolean 199 | gst_ffmpegdeinterlace_sink_setcaps (GstPad * pad, GstCaps * caps) 200 | { 201 | GstFFMpegDeinterlace *deinterlace = 202 | GST_FFMPEGDEINTERLACE (gst_pad_get_parent (pad)); 203 | GstStructure *structure = gst_caps_get_structure (caps, 0); 204 | const gchar *imode; 205 | AVCodecContext *ctx; 206 | GstCaps *src_caps; 207 | gboolean ret; 208 | 209 | /* FIXME: use GstVideoInfo etc. */ 210 | if (!gst_structure_get_int (structure, "width", &deinterlace->width)) 211 | return FALSE; 212 | if (!gst_structure_get_int (structure, "height", &deinterlace->height)) 213 | return FALSE; 214 | 215 | deinterlace->interlaced = FALSE; 216 | imode = gst_structure_get_string (structure, "interlace-mode"); 217 | if (imode && (!strcmp (imode, "interleaved") || !strcmp (imode, "mixed"))) { 218 | deinterlace->interlaced = TRUE; 219 | } 220 | gst_ffmpegdeinterlace_update_passthrough (deinterlace); 221 | 222 | ctx = avcodec_alloc_context3 (NULL); 223 | ctx->width = deinterlace->width; 224 | ctx->height = deinterlace->height; 225 | ctx->pix_fmt = AV_PIX_FMT_NB; 226 | gst_ffmpeg_caps_with_codectype (AVMEDIA_TYPE_VIDEO, caps, ctx); 227 | if (ctx->pix_fmt == AV_PIX_FMT_NB) { 228 | gst_ffmpeg_avcodec_close (ctx); 229 | av_free (ctx); 230 | return FALSE; 231 | } 232 | 233 | deinterlace->pixfmt = ctx->pix_fmt; 234 | 235 | av_free (ctx); 236 | 237 | deinterlace->to_size = 238 | av_image_get_buffer_size (deinterlace->pixfmt, deinterlace->width, 239 | deinterlace->height, 1); 240 | 241 | src_caps = gst_caps_copy (caps); 242 | gst_caps_set_simple (src_caps, "interlace-mode", G_TYPE_STRING, 243 | deinterlace->interlaced ? "progressive" : imode, NULL); 244 | ret = gst_pad_set_caps (deinterlace->srcpad, src_caps); 245 | gst_caps_unref (src_caps); 246 | 247 | return ret; 248 | } 249 | 250 | static gboolean 251 | gst_ffmpegdeinterlace_sink_event (GstPad * pad, GstObject * parent, 252 | GstEvent * event) 253 | { 254 | GstFFMpegDeinterlace *deinterlace = GST_FFMPEGDEINTERLACE (parent); 255 | gboolean ret = FALSE; 256 | 257 | switch (GST_EVENT_TYPE (event)) { 258 | case GST_EVENT_CAPS: 259 | { 260 | GstCaps *caps; 261 | 262 | gst_event_parse_caps (event, &caps); 263 | ret = gst_ffmpegdeinterlace_sink_setcaps (pad, caps); 264 | gst_event_unref (event); 265 | break; 266 | } 267 | default: 268 | ret = gst_pad_push_event (deinterlace->srcpad, event); 269 | break; 270 | } 271 | 272 | return ret; 273 | } 274 | 275 | static void 276 | gst_ffmpegdeinterlace_init (GstFFMpegDeinterlace * deinterlace) 277 | { 278 | deinterlace->sinkpad = 279 | gst_pad_new_from_static_template (&sink_factory, "sink"); 280 | gst_pad_set_event_function (deinterlace->sinkpad, 281 | gst_ffmpegdeinterlace_sink_event); 282 | gst_pad_set_chain_function (deinterlace->sinkpad, 283 | gst_ffmpegdeinterlace_chain); 284 | gst_element_add_pad (GST_ELEMENT (deinterlace), deinterlace->sinkpad); 285 | 286 | deinterlace->srcpad = gst_pad_new_from_static_template (&src_factory, "src"); 287 | gst_element_add_pad (GST_ELEMENT (deinterlace), deinterlace->srcpad); 288 | 289 | deinterlace->pixfmt = AV_PIX_FMT_NB; 290 | 291 | deinterlace->interlaced = FALSE; 292 | deinterlace->passthrough = FALSE; 293 | deinterlace->reconfigure = FALSE; 294 | deinterlace->mode = DEFAULT_MODE; 295 | deinterlace->new_mode = -1; 296 | deinterlace->last_width = -1; 297 | deinterlace->last_height = -1; 298 | deinterlace->last_pixfmt = AV_PIX_FMT_NONE; 299 | } 300 | 301 | static void 302 | delete_filter_graph (GstFFMpegDeinterlace * deinterlace) 303 | { 304 | if (deinterlace->filter_graph) { 305 | av_frame_free (&deinterlace->filter_frame); 306 | avfilter_graph_free (&deinterlace->filter_graph); 307 | } 308 | } 309 | 310 | static void 311 | gst_ffmpegdeinterlace_dispose (GObject * obj) 312 | { 313 | GstFFMpegDeinterlace *deinterlace = GST_FFMPEGDEINTERLACE (obj); 314 | 315 | delete_filter_graph (deinterlace); 316 | 317 | G_OBJECT_CLASS (gst_ffmpegdeinterlace_parent_class)->dispose (obj); 318 | } 319 | 320 | static int 321 | init_filter_graph (GstFFMpegDeinterlace * deinterlace, 322 | enum AVPixelFormat pixfmt, int width, int height) 323 | { 324 | AVFilterInOut *inputs = NULL, *outputs = NULL; 325 | char args[512]; 326 | int res; 327 | 328 | delete_filter_graph (deinterlace); 329 | deinterlace->filter_graph = avfilter_graph_alloc (); 330 | snprintf (args, sizeof (args), 331 | "buffer=video_size=%dx%d:pix_fmt=%d:time_base=1/1:pixel_aspect=0/1[in];" 332 | "[in]yadif[out];" "[out]buffersink", width, height, pixfmt); 333 | res = 334 | avfilter_graph_parse2 (deinterlace->filter_graph, args, &inputs, 335 | &outputs); 336 | if (res < 0) 337 | return res; 338 | if (inputs || outputs) 339 | return -1; 340 | res = avfilter_graph_config (deinterlace->filter_graph, NULL); 341 | if (res < 0) 342 | return res; 343 | 344 | deinterlace->buffersrc_ctx = 345 | avfilter_graph_get_filter (deinterlace->filter_graph, "Parsed_buffer_0"); 346 | deinterlace->buffersink_ctx = 347 | avfilter_graph_get_filter (deinterlace->filter_graph, 348 | "Parsed_buffersink_2"); 349 | if (!deinterlace->buffersrc_ctx || !deinterlace->buffersink_ctx) 350 | return -1; 351 | deinterlace->filter_frame = av_frame_alloc (); 352 | deinterlace->last_width = width; 353 | deinterlace->last_height = height; 354 | deinterlace->last_pixfmt = pixfmt; 355 | 356 | return 0; 357 | } 358 | 359 | static int 360 | process_filter_graph (GstFFMpegDeinterlace * deinterlace, AVFrame * dst, 361 | const AVFrame * src, enum AVPixelFormat pixfmt, int width, int height) 362 | { 363 | int res; 364 | 365 | if (!deinterlace->filter_graph || width != deinterlace->last_width || 366 | height != deinterlace->last_height 367 | || pixfmt != deinterlace->last_pixfmt) { 368 | res = init_filter_graph (deinterlace, pixfmt, width, height); 369 | if (res < 0) 370 | return res; 371 | } 372 | 373 | memcpy (deinterlace->filter_frame->data, src->data, sizeof (src->data)); 374 | memcpy (deinterlace->filter_frame->linesize, src->linesize, 375 | sizeof (src->linesize)); 376 | deinterlace->filter_frame->width = width; 377 | deinterlace->filter_frame->height = height; 378 | deinterlace->filter_frame->format = pixfmt; 379 | res = 380 | av_buffersrc_add_frame (deinterlace->buffersrc_ctx, 381 | deinterlace->filter_frame); 382 | if (res < 0) 383 | return res; 384 | res = 385 | av_buffersink_get_frame (deinterlace->buffersink_ctx, 386 | deinterlace->filter_frame); 387 | if (res < 0) 388 | return res; 389 | av_image_copy (dst->data, dst->linesize, 390 | (const uint8_t **) deinterlace->filter_frame->data, 391 | deinterlace->filter_frame->linesize, pixfmt, width, height); 392 | av_frame_unref (deinterlace->filter_frame); 393 | 394 | return 0; 395 | } 396 | 397 | static GstFlowReturn 398 | gst_ffmpegdeinterlace_chain (GstPad * pad, GstObject * parent, 399 | GstBuffer * inbuf) 400 | { 401 | GstFFMpegDeinterlace *deinterlace = GST_FFMPEGDEINTERLACE (parent); 402 | GstBuffer *outbuf = NULL; 403 | GstFlowReturn result; 404 | GstMapInfo from_map, to_map; 405 | 406 | GST_OBJECT_LOCK (deinterlace); 407 | if (deinterlace->reconfigure) { 408 | GstCaps *caps; 409 | 410 | if ((gint) deinterlace->new_mode != -1) 411 | deinterlace->mode = deinterlace->new_mode; 412 | deinterlace->new_mode = -1; 413 | 414 | deinterlace->reconfigure = FALSE; 415 | GST_OBJECT_UNLOCK (deinterlace); 416 | if ((caps = gst_pad_get_current_caps (deinterlace->srcpad))) { 417 | gst_ffmpegdeinterlace_sink_setcaps (deinterlace->sinkpad, caps); 418 | gst_caps_unref (caps); 419 | } 420 | } else { 421 | GST_OBJECT_UNLOCK (deinterlace); 422 | } 423 | 424 | if (deinterlace->passthrough) 425 | return gst_pad_push (deinterlace->srcpad, inbuf); 426 | 427 | outbuf = gst_buffer_new_and_alloc (deinterlace->to_size); 428 | 429 | gst_buffer_map (inbuf, &from_map, GST_MAP_READ); 430 | gst_ffmpeg_avpicture_fill (&deinterlace->from_frame, from_map.data, 431 | deinterlace->pixfmt, deinterlace->width, deinterlace->height); 432 | 433 | gst_buffer_map (outbuf, &to_map, GST_MAP_WRITE); 434 | gst_ffmpeg_avpicture_fill (&deinterlace->to_frame, to_map.data, 435 | deinterlace->pixfmt, deinterlace->width, deinterlace->height); 436 | 437 | process_filter_graph (deinterlace, &deinterlace->to_frame, 438 | &deinterlace->from_frame, deinterlace->pixfmt, deinterlace->width, 439 | deinterlace->height); 440 | gst_buffer_unmap (outbuf, &to_map); 441 | gst_buffer_unmap (inbuf, &from_map); 442 | 443 | gst_buffer_copy_into (outbuf, inbuf, GST_BUFFER_COPY_TIMESTAMPS, 0, -1); 444 | 445 | result = gst_pad_push (deinterlace->srcpad, outbuf); 446 | 447 | gst_buffer_unref (inbuf); 448 | 449 | return result; 450 | } 451 | 452 | gboolean 453 | gst_ffmpegdeinterlace_register (GstPlugin * plugin) 454 | { 455 | return gst_element_register (plugin, "avdeinterlace", 456 | GST_RANK_NONE, GST_TYPE_FFMPEGDEINTERLACE); 457 | } 458 | 459 | static void 460 | gst_ffmpegdeinterlace_set_property (GObject * object, guint prop_id, 461 | const GValue * value, GParamSpec * pspec) 462 | { 463 | GstFFMpegDeinterlace *self; 464 | 465 | g_return_if_fail (GST_IS_FFMPEGDEINTERLACE (object)); 466 | self = GST_FFMPEGDEINTERLACE (object); 467 | 468 | switch (prop_id) { 469 | case PROP_MODE:{ 470 | gint new_mode; 471 | 472 | GST_OBJECT_LOCK (self); 473 | new_mode = g_value_get_enum (value); 474 | if (self->mode != new_mode && gst_pad_has_current_caps (self->srcpad)) { 475 | self->reconfigure = TRUE; 476 | self->new_mode = new_mode; 477 | } else { 478 | self->mode = new_mode; 479 | gst_ffmpegdeinterlace_update_passthrough (self); 480 | } 481 | GST_OBJECT_UNLOCK (self); 482 | break; 483 | } 484 | default: 485 | G_OBJECT_WARN_INVALID_PROPERTY_ID (self, prop_id, pspec); 486 | } 487 | 488 | } 489 | 490 | static void 491 | gst_ffmpegdeinterlace_get_property (GObject * object, guint prop_id, 492 | GValue * value, GParamSpec * pspec) 493 | { 494 | GstFFMpegDeinterlace *self; 495 | 496 | g_return_if_fail (GST_IS_FFMPEGDEINTERLACE (object)); 497 | self = GST_FFMPEGDEINTERLACE (object); 498 | 499 | switch (prop_id) { 500 | case PROP_MODE: 501 | g_value_set_enum (value, self->mode); 502 | break; 503 | default: 504 | G_OBJECT_WARN_INVALID_PROPERTY_ID (self, prop_id, pspec); 505 | } 506 | } 507 | -------------------------------------------------------------------------------- /ext/libav/gstavprotocol.c: -------------------------------------------------------------------------------- 1 | /* GStreamer 2 | * Copyright (C) <1999> Erik Walthinsen 3 | * <2006> Edward Hervey 4 | * 5 | * This library is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Library General Public 7 | * License as published by the Free Software Foundation; either 8 | * version 2 of the License, or (at your option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Library General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Library General Public 16 | * License along with this library; if not, write to the 17 | * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, 18 | * Boston, MA 02110-1301, USA. 19 | */ 20 | 21 | #ifdef HAVE_CONFIG_H 22 | #include "config.h" 23 | #endif 24 | #include 25 | #include 26 | 27 | #include 28 | 29 | #include 30 | 31 | #include "gstav.h" 32 | #include "gstavprotocol.h" 33 | 34 | typedef struct _GstProtocolInfo GstProtocolInfo; 35 | 36 | struct _GstProtocolInfo 37 | { 38 | GstPad *pad; 39 | 40 | guint64 offset; 41 | gboolean eos; 42 | gint set_streamheader; 43 | }; 44 | 45 | static int 46 | gst_ffmpegdata_peek (void *priv_data, unsigned char *buf, int size) 47 | { 48 | GstProtocolInfo *info; 49 | GstBuffer *inbuf = NULL; 50 | GstFlowReturn ret; 51 | int total = 0; 52 | 53 | info = (GstProtocolInfo *) priv_data; 54 | 55 | GST_DEBUG ("Pulling %d bytes at position %" G_GUINT64_FORMAT, size, 56 | info->offset); 57 | 58 | ret = gst_pad_pull_range (info->pad, info->offset, (guint) size, &inbuf); 59 | 60 | switch (ret) { 61 | case GST_FLOW_OK: 62 | total = (gint) gst_buffer_get_size (inbuf); 63 | gst_buffer_extract (inbuf, 0, buf, total); 64 | gst_buffer_unref (inbuf); 65 | break; 66 | case GST_FLOW_EOS: 67 | total = 0; 68 | break; 69 | case GST_FLOW_FLUSHING: 70 | total = -1; 71 | break; 72 | default: 73 | case GST_FLOW_ERROR: 74 | total = -2; 75 | break; 76 | } 77 | 78 | GST_DEBUG ("Got %d (%s) return result %d", ret, gst_flow_get_name (ret), 79 | total); 80 | 81 | return total; 82 | } 83 | 84 | static int 85 | gst_ffmpegdata_read (void *priv_data, unsigned char *buf, int size) 86 | { 87 | gint res; 88 | GstProtocolInfo *info; 89 | 90 | info = (GstProtocolInfo *) priv_data; 91 | 92 | GST_DEBUG ("Reading %d bytes of data at position %" G_GUINT64_FORMAT, size, 93 | info->offset); 94 | 95 | res = gst_ffmpegdata_peek (priv_data, buf, size); 96 | if (res >= 0) 97 | info->offset += res; 98 | 99 | GST_DEBUG ("Returning %d bytes", res); 100 | 101 | return res; 102 | } 103 | 104 | static int 105 | gst_ffmpegdata_write (void *priv_data, uint8_t * buf, int size) 106 | { 107 | GstProtocolInfo *info; 108 | GstBuffer *outbuf; 109 | 110 | GST_DEBUG ("Writing %d bytes", size); 111 | info = (GstProtocolInfo *) priv_data; 112 | 113 | /* create buffer and push data further */ 114 | outbuf = gst_buffer_new_and_alloc (size); 115 | 116 | gst_buffer_fill (outbuf, 0, buf, size); 117 | 118 | if (gst_pad_push (info->pad, outbuf) != GST_FLOW_OK) 119 | return 0; 120 | 121 | info->offset += size; 122 | return size; 123 | } 124 | 125 | static int64_t 126 | gst_ffmpegdata_seek (void *priv_data, int64_t pos, int whence) 127 | { 128 | GstProtocolInfo *info; 129 | guint64 newpos = 0, oldpos; 130 | 131 | GST_DEBUG ("Seeking to %" G_GINT64_FORMAT ", whence=%d", 132 | (gint64) pos, whence); 133 | 134 | info = (GstProtocolInfo *) priv_data; 135 | 136 | /* TODO : if we are push-based, we need to return sensible info */ 137 | 138 | if (GST_PAD_IS_SINK (info->pad)) { 139 | /* sinkpad */ 140 | switch (whence) { 141 | case SEEK_SET: 142 | newpos = (guint64) pos; 143 | break; 144 | case SEEK_CUR: 145 | newpos = info->offset + pos; 146 | break; 147 | case SEEK_END: 148 | case AVSEEK_SIZE: 149 | /* ffmpeg wants to know the current end position in bytes ! */ 150 | { 151 | gint64 duration; 152 | 153 | GST_DEBUG ("Seek end"); 154 | 155 | if (gst_pad_is_linked (info->pad)) 156 | if (gst_pad_query_duration (GST_PAD_PEER (info->pad), 157 | GST_FORMAT_BYTES, &duration)) 158 | newpos = ((guint64) duration) + pos; 159 | } 160 | break; 161 | default: 162 | g_assert (0); 163 | break; 164 | } 165 | /* FIXME : implement case for push-based behaviour */ 166 | if (whence != AVSEEK_SIZE) 167 | info->offset = newpos; 168 | } else if (GST_PAD_IS_SRC (info->pad)) { 169 | GstSegment segment; 170 | 171 | oldpos = info->offset; 172 | 173 | /* srcpad */ 174 | switch (whence) { 175 | case SEEK_SET: 176 | { 177 | info->offset = (guint64) pos; 178 | break; 179 | } 180 | case SEEK_CUR: 181 | info->offset += pos; 182 | break; 183 | default: 184 | break; 185 | } 186 | newpos = info->offset; 187 | 188 | if (newpos != oldpos) { 189 | gst_segment_init (&segment, GST_FORMAT_BYTES); 190 | segment.start = newpos; 191 | segment.time = newpos; 192 | gst_pad_push_event (info->pad, gst_event_new_segment (&segment)); 193 | } 194 | } else { 195 | g_assert_not_reached (); 196 | } 197 | 198 | GST_DEBUG ("Now at offset %" G_GUINT64_FORMAT " (returning %" G_GUINT64_FORMAT 199 | ")", info->offset, newpos); 200 | return newpos; 201 | } 202 | 203 | int 204 | gst_ffmpegdata_close (AVIOContext * h) 205 | { 206 | GstProtocolInfo *info; 207 | 208 | if (h == NULL) 209 | return 0; 210 | 211 | info = (GstProtocolInfo *) h->opaque; 212 | if (info == NULL) 213 | return 0; 214 | 215 | GST_LOG ("Closing file"); 216 | 217 | if (GST_PAD_IS_SRC (info->pad)) { 218 | /* send EOS - that closes down the stream */ 219 | gst_pad_push_event (info->pad, gst_event_new_eos ()); 220 | } 221 | 222 | /* clean up data */ 223 | g_free (info); 224 | h->opaque = NULL; 225 | 226 | av_freep (&h->buffer); 227 | av_free (h); 228 | 229 | return 0; 230 | } 231 | 232 | int 233 | gst_ffmpegdata_open (GstPad * pad, int flags, AVIOContext ** context) 234 | { 235 | GstProtocolInfo *info; 236 | static const int buffer_size = 4096; 237 | unsigned char *buffer = NULL; 238 | 239 | info = g_new0 (GstProtocolInfo, 1); 240 | 241 | info->set_streamheader = flags & GST_FFMPEG_URL_STREAMHEADER; 242 | flags &= ~GST_FFMPEG_URL_STREAMHEADER; 243 | 244 | /* we don't support R/W together */ 245 | if ((flags & AVIO_FLAG_WRITE) && (flags & AVIO_FLAG_READ)) { 246 | GST_WARNING ("Only read-only or write-only are supported"); 247 | g_free (info); 248 | return -EINVAL; 249 | } 250 | 251 | /* make sure we're a pad and that we're of the right type */ 252 | g_return_val_if_fail (GST_IS_PAD (pad), -EINVAL); 253 | 254 | if ((flags & AVIO_FLAG_READ)) 255 | g_return_val_if_fail (GST_PAD_IS_SINK (pad), -EINVAL); 256 | if ((flags & AVIO_FLAG_WRITE)) 257 | g_return_val_if_fail (GST_PAD_IS_SRC (pad), -EINVAL); 258 | 259 | info->eos = FALSE; 260 | info->pad = pad; 261 | info->offset = 0; 262 | 263 | buffer = av_malloc (buffer_size); 264 | if (buffer == NULL) { 265 | GST_WARNING ("Failed to allocate buffer"); 266 | g_free (info); 267 | return -ENOMEM; 268 | } 269 | 270 | *context = 271 | avio_alloc_context (buffer, buffer_size, flags, (void *) info, 272 | gst_ffmpegdata_read, gst_ffmpegdata_write, gst_ffmpegdata_seek); 273 | if (*context == NULL) { 274 | GST_WARNING ("Failed to allocate memory"); 275 | g_free (info); 276 | av_free (buffer); 277 | return -ENOMEM; 278 | } 279 | (*context)->seekable = AVIO_SEEKABLE_NORMAL; 280 | if (!(flags & AVIO_FLAG_WRITE)) { 281 | (*context)->buf_ptr = (*context)->buf_end; 282 | (*context)->write_flag = 0; 283 | } 284 | 285 | return 0; 286 | } 287 | 288 | /* specialized protocol for cross-thread pushing, 289 | * based on ffmpeg's pipe protocol */ 290 | 291 | static int 292 | gst_ffmpeg_pipe_read (void *priv_data, uint8_t * buf, int size) 293 | { 294 | GstFFMpegPipe *ffpipe; 295 | guint available; 296 | 297 | ffpipe = (GstFFMpegPipe *) priv_data; 298 | 299 | GST_LOG ("requested size %d", size); 300 | 301 | GST_FFMPEG_PIPE_MUTEX_LOCK (ffpipe); 302 | 303 | GST_LOG ("requested size %d", size); 304 | 305 | while ((available = gst_adapter_available (ffpipe->adapter)) < size 306 | && !ffpipe->eos) { 307 | GST_DEBUG ("Available:%d, requested:%d", available, size); 308 | ffpipe->needed = size; 309 | GST_FFMPEG_PIPE_SIGNAL (ffpipe); 310 | GST_FFMPEG_PIPE_WAIT (ffpipe); 311 | } 312 | 313 | size = MIN (available, size); 314 | if (size) { 315 | GST_LOG ("Getting %d bytes", size); 316 | gst_adapter_copy (ffpipe->adapter, buf, 0, size); 317 | gst_adapter_flush (ffpipe->adapter, size); 318 | GST_LOG ("%" G_GSIZE_FORMAT " bytes left in adapter", 319 | gst_adapter_available (ffpipe->adapter)); 320 | ffpipe->needed = 0; 321 | } 322 | GST_FFMPEG_PIPE_MUTEX_UNLOCK (ffpipe); 323 | 324 | return size; 325 | } 326 | 327 | int 328 | gst_ffmpeg_pipe_close (AVIOContext * h) 329 | { 330 | GST_LOG ("Closing pipe"); 331 | 332 | if (h == NULL) 333 | return 0; 334 | 335 | h->opaque = NULL; 336 | av_freep (&h->buffer); 337 | av_free (h); 338 | 339 | return 0; 340 | } 341 | 342 | int 343 | gst_ffmpeg_pipe_open (GstFFMpegPipe * ffpipe, int flags, AVIOContext ** context) 344 | { 345 | static const int buffer_size = 4096; 346 | unsigned char *buffer = NULL; 347 | 348 | /* sanity check */ 349 | g_return_val_if_fail (GST_IS_ADAPTER (ffpipe->adapter), -EINVAL); 350 | 351 | buffer = av_malloc (buffer_size); 352 | if (buffer == NULL) { 353 | GST_WARNING ("Failed to allocate buffer"); 354 | return -ENOMEM; 355 | } 356 | 357 | *context = 358 | avio_alloc_context (buffer, buffer_size, 0, (void *) ffpipe, 359 | gst_ffmpeg_pipe_read, NULL, NULL); 360 | if (*context == NULL) { 361 | GST_WARNING ("Failed to allocate memory"); 362 | av_free (buffer); 363 | return -ENOMEM; 364 | } 365 | (*context)->seekable = 0; 366 | (*context)->buf_ptr = (*context)->buf_end; 367 | 368 | return 0; 369 | } 370 | -------------------------------------------------------------------------------- /ext/libav/gstavprotocol.h: -------------------------------------------------------------------------------- 1 | /* GStreamer 2 | * Copyright (C) <2006> Mark Nauwelaerts 3 | * 4 | * This library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Library General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2 of the License, or (at your option) any later version. 8 | * 9 | * This library is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Library General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Library General Public 15 | * License along with this library; if not, write to the 16 | * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, 17 | * Boston, MA 02110-1301, USA. 18 | */ 19 | 20 | 21 | #ifndef __GST_FFMPEGPROTOCOL_H__ 22 | #define __GST_FFMPEGPROTOCOL_H__ 23 | 24 | #include 25 | #include "gstav.h" 26 | 27 | G_BEGIN_DECLS 28 | 29 | /* pipe protocol helpers */ 30 | #define GST_FFMPEG_PIPE_MUTEX_LOCK(m) G_STMT_START { \ 31 | GST_LOG ("locking tlock from thread %p", g_thread_self ()); \ 32 | g_mutex_lock (&m->tlock); \ 33 | GST_LOG ("locked tlock from thread %p", g_thread_self ()); \ 34 | } G_STMT_END 35 | 36 | #define GST_FFMPEG_PIPE_MUTEX_UNLOCK(m) G_STMT_START { \ 37 | GST_LOG ("unlocking tlock from thread %p", g_thread_self ()); \ 38 | g_mutex_unlock (&m->tlock); \ 39 | } G_STMT_END 40 | 41 | #define GST_FFMPEG_PIPE_WAIT(m) G_STMT_START { \ 42 | GST_LOG ("thread %p waiting", g_thread_self ()); \ 43 | g_cond_wait (&m->cond, &m->tlock); \ 44 | } G_STMT_END 45 | 46 | #define GST_FFMPEG_PIPE_SIGNAL(m) G_STMT_START { \ 47 | GST_LOG ("signalling from thread %p", g_thread_self ()); \ 48 | g_cond_signal (&m->cond); \ 49 | } G_STMT_END 50 | 51 | typedef struct _GstFFMpegPipe GstFFMpegPipe; 52 | 53 | struct _GstFFMpegPipe 54 | { 55 | /* lock for syncing */ 56 | GMutex tlock; 57 | /* with TLOCK */ 58 | /* signals counterpart thread to have a look */ 59 | GCond cond; 60 | /* seen eos */ 61 | gboolean eos; 62 | /* flowreturn obtained by src task */ 63 | GstFlowReturn srcresult; 64 | /* adpater collecting data */ 65 | GstAdapter *adapter; 66 | /* amount needed in adapter by src task */ 67 | guint needed; 68 | }; 69 | 70 | int gst_ffmpeg_pipe_open (GstFFMpegPipe *ffpipe, int flags, AVIOContext ** context); 71 | int gst_ffmpeg_pipe_close (AVIOContext * h); 72 | 73 | int gst_ffmpegdata_open (GstPad * pad, int flags, AVIOContext ** context); 74 | int gst_ffmpegdata_close (AVIOContext * h); 75 | 76 | G_END_DECLS 77 | 78 | #endif /* __GST_FFMPEGPROTOCOL_H__ */ 79 | -------------------------------------------------------------------------------- /ext/libav/gstavutils.c: -------------------------------------------------------------------------------- 1 | /* GStreamer 2 | * Copyright (c) 2009 Edward Hervey 3 | * 4 | * This library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Library General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2 of the License, or (at your option) any later version. 8 | * 9 | * This library is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Library General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Library General Public 15 | * License along with this library; if not, write to the 16 | * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, 17 | * Boston, MA 02110-1301, USA. 18 | */ 19 | 20 | #ifdef HAVE_CONFIG_H 21 | #include "config.h" 22 | #endif 23 | #include "gstavutils.h" 24 | #ifdef HAVE_UNISTD_H 25 | #include 26 | #endif 27 | #ifdef __APPLE__ 28 | #include 29 | #endif 30 | #ifdef __MINGW32__ 31 | #include 32 | #endif 33 | 34 | #include 35 | 36 | const gchar * 37 | gst_ffmpeg_get_codecid_longname (enum AVCodecID codec_id) 38 | { 39 | AVCodec *codec; 40 | /* Let's use what ffmpeg can provide us */ 41 | 42 | if ((codec = avcodec_find_decoder (codec_id)) || 43 | (codec = avcodec_find_encoder (codec_id))) 44 | return codec->long_name; 45 | return NULL; 46 | } 47 | 48 | gint 49 | av_smp_format_depth (enum AVSampleFormat smp_fmt) 50 | { 51 | gint depth = -1; 52 | switch (smp_fmt) { 53 | case AV_SAMPLE_FMT_U8: 54 | case AV_SAMPLE_FMT_U8P: 55 | depth = 1; 56 | break; 57 | case AV_SAMPLE_FMT_S16: 58 | case AV_SAMPLE_FMT_S16P: 59 | depth = 2; 60 | break; 61 | case AV_SAMPLE_FMT_S32: 62 | case AV_SAMPLE_FMT_S32P: 63 | case AV_SAMPLE_FMT_FLT: 64 | case AV_SAMPLE_FMT_FLTP: 65 | depth = 4; 66 | break; 67 | case AV_SAMPLE_FMT_DBL: 68 | case AV_SAMPLE_FMT_DBLP: 69 | depth = 8; 70 | break; 71 | default: 72 | GST_ERROR ("UNHANDLED SAMPLE FORMAT !"); 73 | break; 74 | } 75 | return depth; 76 | } 77 | 78 | 79 | /* 80 | * Fill in pointers to memory in a AVFrame, where 81 | * everything is aligned by 4 (as required by X). 82 | * This is mostly a copy from imgconvert.c with some 83 | * small changes. 84 | */ 85 | 86 | #define FF_COLOR_RGB 0 /* RGB color space */ 87 | #define FF_COLOR_GRAY 1 /* gray color space */ 88 | #define FF_COLOR_YUV 2 /* YUV color space. 16 <= Y <= 235, 16 <= U, V <= 240 */ 89 | #define FF_COLOR_YUV_JPEG 3 /* YUV color space. 0 <= Y <= 255, 0 <= U, V <= 255 */ 90 | 91 | #define FF_PIXEL_PLANAR 0 /* each channel has one component in AVFrame */ 92 | #define FF_PIXEL_PACKED 1 /* only one components containing all the channels */ 93 | #define FF_PIXEL_PALETTE 2 /* one components containing indexes for a palette */ 94 | 95 | typedef struct PixFmtInfo 96 | { 97 | const char *name; 98 | uint8_t nb_channels; /* number of channels (including alpha) */ 99 | uint8_t color_type; /* color type (see FF_COLOR_xxx constants) */ 100 | uint8_t pixel_type; /* pixel storage type (see FF_PIXEL_xxx constants) */ 101 | uint8_t is_alpha:1; /* true if alpha can be specified */ 102 | uint8_t x_chroma_shift; /* X chroma subsampling factor is 2 ^ shift */ 103 | uint8_t y_chroma_shift; /* Y chroma subsampling factor is 2 ^ shift */ 104 | uint8_t depth; /* bit depth of the color components */ 105 | } PixFmtInfo; 106 | 107 | 108 | /* this table gives more information about formats */ 109 | static PixFmtInfo pix_fmt_info[AV_PIX_FMT_NB]; 110 | void 111 | gst_ffmpeg_init_pix_fmt_info (void) 112 | { 113 | /* YUV formats */ 114 | pix_fmt_info[AV_PIX_FMT_YUV420P].name = g_strdup ("yuv420p"); 115 | pix_fmt_info[AV_PIX_FMT_YUV420P].nb_channels = 3; 116 | pix_fmt_info[AV_PIX_FMT_YUV420P].color_type = FF_COLOR_YUV; 117 | pix_fmt_info[AV_PIX_FMT_YUV420P].pixel_type = FF_PIXEL_PLANAR; 118 | pix_fmt_info[AV_PIX_FMT_YUV420P].depth = 8, 119 | pix_fmt_info[AV_PIX_FMT_YUV420P].x_chroma_shift = 1, 120 | pix_fmt_info[AV_PIX_FMT_YUV420P].y_chroma_shift = 1; 121 | 122 | pix_fmt_info[AV_PIX_FMT_YUV422P].name = g_strdup ("yuv422p"); 123 | pix_fmt_info[AV_PIX_FMT_YUV422P].nb_channels = 3; 124 | pix_fmt_info[AV_PIX_FMT_YUV422P].color_type = FF_COLOR_YUV; 125 | pix_fmt_info[AV_PIX_FMT_YUV422P].pixel_type = FF_PIXEL_PLANAR; 126 | pix_fmt_info[AV_PIX_FMT_YUV422P].depth = 8; 127 | pix_fmt_info[AV_PIX_FMT_YUV422P].x_chroma_shift = 1; 128 | pix_fmt_info[AV_PIX_FMT_YUV422P].y_chroma_shift = 0; 129 | 130 | pix_fmt_info[AV_PIX_FMT_YUV444P].name = g_strdup ("yuv444p"); 131 | pix_fmt_info[AV_PIX_FMT_YUV444P].nb_channels = 3; 132 | pix_fmt_info[AV_PIX_FMT_YUV444P].color_type = FF_COLOR_YUV; 133 | pix_fmt_info[AV_PIX_FMT_YUV444P].pixel_type = FF_PIXEL_PLANAR; 134 | pix_fmt_info[AV_PIX_FMT_YUV444P].depth = 8; 135 | pix_fmt_info[AV_PIX_FMT_YUV444P].x_chroma_shift = 0; 136 | pix_fmt_info[AV_PIX_FMT_YUV444P].y_chroma_shift = 0; 137 | 138 | pix_fmt_info[AV_PIX_FMT_YUYV422].name = g_strdup ("yuv422"); 139 | pix_fmt_info[AV_PIX_FMT_YUYV422].nb_channels = 1; 140 | pix_fmt_info[AV_PIX_FMT_YUYV422].color_type = FF_COLOR_YUV; 141 | pix_fmt_info[AV_PIX_FMT_YUYV422].pixel_type = FF_PIXEL_PACKED; 142 | pix_fmt_info[AV_PIX_FMT_YUYV422].depth = 8; 143 | pix_fmt_info[AV_PIX_FMT_YUYV422].x_chroma_shift = 1; 144 | pix_fmt_info[AV_PIX_FMT_YUYV422].y_chroma_shift = 0; 145 | 146 | pix_fmt_info[AV_PIX_FMT_YUV410P].name = g_strdup ("yuv410p"); 147 | pix_fmt_info[AV_PIX_FMT_YUV410P].nb_channels = 3; 148 | pix_fmt_info[AV_PIX_FMT_YUV410P].color_type = FF_COLOR_YUV; 149 | pix_fmt_info[AV_PIX_FMT_YUV410P].pixel_type = FF_PIXEL_PLANAR; 150 | pix_fmt_info[AV_PIX_FMT_YUV410P].depth = 8; 151 | pix_fmt_info[AV_PIX_FMT_YUV410P].x_chroma_shift = 2; 152 | pix_fmt_info[AV_PIX_FMT_YUV410P].y_chroma_shift = 2; 153 | 154 | pix_fmt_info[AV_PIX_FMT_YUV411P].name = g_strdup ("yuv411p"); 155 | pix_fmt_info[AV_PIX_FMT_YUV411P].nb_channels = 3; 156 | pix_fmt_info[AV_PIX_FMT_YUV411P].color_type = FF_COLOR_YUV; 157 | pix_fmt_info[AV_PIX_FMT_YUV411P].pixel_type = FF_PIXEL_PLANAR; 158 | pix_fmt_info[AV_PIX_FMT_YUV411P].depth = 8; 159 | pix_fmt_info[AV_PIX_FMT_YUV411P].x_chroma_shift = 2; 160 | pix_fmt_info[AV_PIX_FMT_YUV411P].y_chroma_shift = 0; 161 | 162 | /* JPEG YUV */ 163 | pix_fmt_info[AV_PIX_FMT_YUVJ420P].name = g_strdup ("yuvj420p"); 164 | pix_fmt_info[AV_PIX_FMT_YUVJ420P].nb_channels = 3; 165 | pix_fmt_info[AV_PIX_FMT_YUVJ420P].color_type = FF_COLOR_YUV_JPEG; 166 | pix_fmt_info[AV_PIX_FMT_YUVJ420P].pixel_type = FF_PIXEL_PLANAR; 167 | pix_fmt_info[AV_PIX_FMT_YUVJ420P].depth = 8; 168 | pix_fmt_info[AV_PIX_FMT_YUVJ420P].x_chroma_shift = 1; 169 | pix_fmt_info[AV_PIX_FMT_YUVJ420P].y_chroma_shift = 1; 170 | 171 | pix_fmt_info[AV_PIX_FMT_YUVJ422P].name = g_strdup ("yuvj422p"); 172 | pix_fmt_info[AV_PIX_FMT_YUVJ422P].nb_channels = 3; 173 | pix_fmt_info[AV_PIX_FMT_YUVJ422P].color_type = FF_COLOR_YUV_JPEG; 174 | pix_fmt_info[AV_PIX_FMT_YUVJ422P].pixel_type = FF_PIXEL_PLANAR; 175 | pix_fmt_info[AV_PIX_FMT_YUVJ422P].depth = 8; 176 | pix_fmt_info[AV_PIX_FMT_YUVJ422P].x_chroma_shift = 1; 177 | pix_fmt_info[AV_PIX_FMT_YUVJ422P].y_chroma_shift = 0; 178 | 179 | pix_fmt_info[AV_PIX_FMT_YUVJ444P].name = g_strdup ("yuvj444p"); 180 | pix_fmt_info[AV_PIX_FMT_YUVJ444P].nb_channels = 3; 181 | pix_fmt_info[AV_PIX_FMT_YUVJ444P].color_type = FF_COLOR_YUV_JPEG; 182 | pix_fmt_info[AV_PIX_FMT_YUVJ444P].pixel_type = FF_PIXEL_PLANAR; 183 | pix_fmt_info[AV_PIX_FMT_YUVJ444P].depth = 8; 184 | pix_fmt_info[AV_PIX_FMT_YUVJ444P].x_chroma_shift = 0; 185 | pix_fmt_info[AV_PIX_FMT_YUVJ444P].y_chroma_shift = 0; 186 | 187 | /* RGB formats */ 188 | pix_fmt_info[AV_PIX_FMT_RGB24].name = g_strdup ("rgb24"); 189 | pix_fmt_info[AV_PIX_FMT_RGB24].nb_channels = 3; 190 | pix_fmt_info[AV_PIX_FMT_RGB24].color_type = FF_COLOR_RGB; 191 | pix_fmt_info[AV_PIX_FMT_RGB24].pixel_type = FF_PIXEL_PACKED; 192 | pix_fmt_info[AV_PIX_FMT_RGB24].depth = 8; 193 | pix_fmt_info[AV_PIX_FMT_RGB24].x_chroma_shift = 0; 194 | pix_fmt_info[AV_PIX_FMT_RGB24].y_chroma_shift = 0; 195 | 196 | pix_fmt_info[AV_PIX_FMT_BGR24].name = g_strdup ("bgr24"); 197 | pix_fmt_info[AV_PIX_FMT_BGR24].nb_channels = 3; 198 | pix_fmt_info[AV_PIX_FMT_BGR24].color_type = FF_COLOR_RGB; 199 | pix_fmt_info[AV_PIX_FMT_BGR24].pixel_type = FF_PIXEL_PACKED; 200 | pix_fmt_info[AV_PIX_FMT_BGR24].depth = 8; 201 | pix_fmt_info[AV_PIX_FMT_BGR24].x_chroma_shift = 0; 202 | pix_fmt_info[AV_PIX_FMT_BGR24].y_chroma_shift = 0; 203 | 204 | pix_fmt_info[AV_PIX_FMT_RGB32].name = g_strdup ("rgba32"); 205 | pix_fmt_info[AV_PIX_FMT_RGB32].nb_channels = 4; 206 | pix_fmt_info[AV_PIX_FMT_RGB32].is_alpha = 1; 207 | pix_fmt_info[AV_PIX_FMT_RGB32].color_type = FF_COLOR_RGB; 208 | pix_fmt_info[AV_PIX_FMT_RGB32].pixel_type = FF_PIXEL_PACKED; 209 | pix_fmt_info[AV_PIX_FMT_RGB32].depth = 8; 210 | pix_fmt_info[AV_PIX_FMT_RGB32].x_chroma_shift = 0; 211 | pix_fmt_info[AV_PIX_FMT_RGB32].y_chroma_shift = 0; 212 | 213 | pix_fmt_info[AV_PIX_FMT_RGB565].name = g_strdup ("rgb565"); 214 | pix_fmt_info[AV_PIX_FMT_RGB565].nb_channels = 3; 215 | pix_fmt_info[AV_PIX_FMT_RGB565].color_type = FF_COLOR_RGB; 216 | pix_fmt_info[AV_PIX_FMT_RGB565].pixel_type = FF_PIXEL_PACKED; 217 | pix_fmt_info[AV_PIX_FMT_RGB565].depth = 5; 218 | pix_fmt_info[AV_PIX_FMT_RGB565].x_chroma_shift = 0; 219 | pix_fmt_info[AV_PIX_FMT_RGB565].y_chroma_shift = 0; 220 | 221 | pix_fmt_info[AV_PIX_FMT_RGB555].name = g_strdup ("rgb555"); 222 | pix_fmt_info[AV_PIX_FMT_RGB555].nb_channels = 4; 223 | pix_fmt_info[AV_PIX_FMT_RGB555].is_alpha = 1; 224 | pix_fmt_info[AV_PIX_FMT_RGB555].color_type = FF_COLOR_RGB; 225 | pix_fmt_info[AV_PIX_FMT_RGB555].pixel_type = FF_PIXEL_PACKED; 226 | pix_fmt_info[AV_PIX_FMT_RGB555].depth = 5; 227 | pix_fmt_info[AV_PIX_FMT_RGB555].x_chroma_shift = 0; 228 | pix_fmt_info[AV_PIX_FMT_RGB555].y_chroma_shift = 0; 229 | 230 | /* gray / mono formats */ 231 | pix_fmt_info[AV_PIX_FMT_GRAY8].name = g_strdup ("gray"); 232 | pix_fmt_info[AV_PIX_FMT_GRAY8].nb_channels = 1; 233 | pix_fmt_info[AV_PIX_FMT_GRAY8].color_type = FF_COLOR_GRAY; 234 | pix_fmt_info[AV_PIX_FMT_GRAY8].pixel_type = FF_PIXEL_PLANAR; 235 | pix_fmt_info[AV_PIX_FMT_GRAY8].depth = 8; 236 | 237 | pix_fmt_info[AV_PIX_FMT_MONOWHITE].name = g_strdup ("monow"); 238 | pix_fmt_info[AV_PIX_FMT_MONOWHITE].nb_channels = 1; 239 | pix_fmt_info[AV_PIX_FMT_MONOWHITE].color_type = FF_COLOR_GRAY; 240 | pix_fmt_info[AV_PIX_FMT_MONOWHITE].pixel_type = FF_PIXEL_PLANAR; 241 | pix_fmt_info[AV_PIX_FMT_MONOWHITE].depth = 1; 242 | 243 | pix_fmt_info[AV_PIX_FMT_MONOBLACK].name = g_strdup ("monob"); 244 | pix_fmt_info[AV_PIX_FMT_MONOBLACK].nb_channels = 1; 245 | pix_fmt_info[AV_PIX_FMT_MONOBLACK].color_type = FF_COLOR_GRAY; 246 | pix_fmt_info[AV_PIX_FMT_MONOBLACK].pixel_type = FF_PIXEL_PLANAR; 247 | pix_fmt_info[AV_PIX_FMT_MONOBLACK].depth = 1; 248 | 249 | /* paletted formats */ 250 | pix_fmt_info[AV_PIX_FMT_PAL8].name = g_strdup ("pal8"); 251 | pix_fmt_info[AV_PIX_FMT_PAL8].nb_channels = 4; 252 | pix_fmt_info[AV_PIX_FMT_PAL8].is_alpha = 1; 253 | pix_fmt_info[AV_PIX_FMT_PAL8].color_type = FF_COLOR_RGB; 254 | pix_fmt_info[AV_PIX_FMT_PAL8].pixel_type = FF_PIXEL_PALETTE; 255 | pix_fmt_info[AV_PIX_FMT_PAL8].depth = 8; 256 | 257 | pix_fmt_info[AV_PIX_FMT_YUVA420P].name = g_strdup ("yuva420p"); 258 | pix_fmt_info[AV_PIX_FMT_YUVA420P].nb_channels = 4; 259 | pix_fmt_info[AV_PIX_FMT_YUVA420P].is_alpha = 1; 260 | pix_fmt_info[AV_PIX_FMT_YUVA420P].color_type = FF_COLOR_YUV; 261 | pix_fmt_info[AV_PIX_FMT_YUVA420P].pixel_type = FF_PIXEL_PLANAR; 262 | pix_fmt_info[AV_PIX_FMT_YUVA420P].depth = 8, 263 | pix_fmt_info[AV_PIX_FMT_YUVA420P].x_chroma_shift = 1, 264 | pix_fmt_info[AV_PIX_FMT_YUVA420P].y_chroma_shift = 1; 265 | }; 266 | 267 | int 268 | gst_ffmpeg_avpicture_get_size (int pix_fmt, int width, int height) 269 | { 270 | AVFrame dummy_pict; 271 | 272 | return gst_ffmpeg_avpicture_fill (&dummy_pict, NULL, pix_fmt, width, height); 273 | } 274 | 275 | #define GEN_MASK(x) ((1<<(x))-1) 276 | #define ROUND_UP_X(v,x) (((v) + GEN_MASK(x)) & ~GEN_MASK(x)) 277 | #define ROUND_UP_2(x) ROUND_UP_X (x, 1) 278 | #define ROUND_UP_4(x) ROUND_UP_X (x, 2) 279 | #define ROUND_UP_8(x) ROUND_UP_X (x, 3) 280 | #define DIV_ROUND_UP_X(v,x) (((v) + GEN_MASK(x)) >> (x)) 281 | 282 | int 283 | gst_ffmpeg_avpicture_fill (AVFrame * picture, 284 | uint8_t * ptr, enum AVPixelFormat pix_fmt, int width, int height) 285 | { 286 | int size, w2, h2, size2; 287 | int stride, stride2; 288 | PixFmtInfo *pinfo; 289 | 290 | pinfo = &pix_fmt_info[pix_fmt]; 291 | 292 | switch (pix_fmt) { 293 | case AV_PIX_FMT_YUV420P: 294 | case AV_PIX_FMT_YUV422P: 295 | case AV_PIX_FMT_YUV444P: 296 | case AV_PIX_FMT_YUV410P: 297 | case AV_PIX_FMT_YUV411P: 298 | case AV_PIX_FMT_YUVJ420P: 299 | case AV_PIX_FMT_YUVJ422P: 300 | case AV_PIX_FMT_YUVJ444P: 301 | stride = ROUND_UP_4 (width); 302 | h2 = ROUND_UP_X (height, pinfo->y_chroma_shift); 303 | size = stride * h2; 304 | w2 = DIV_ROUND_UP_X (width, pinfo->x_chroma_shift); 305 | stride2 = ROUND_UP_4 (w2); 306 | h2 = DIV_ROUND_UP_X (height, pinfo->y_chroma_shift); 307 | size2 = stride2 * h2; 308 | picture->data[0] = ptr; 309 | picture->data[1] = picture->data[0] + size; 310 | picture->data[2] = picture->data[1] + size2; 311 | picture->data[3] = NULL; 312 | picture->linesize[0] = stride; 313 | picture->linesize[1] = stride2; 314 | picture->linesize[2] = stride2; 315 | picture->linesize[3] = 0; 316 | GST_DEBUG ("planes %d %d %d", 0, size, size + size2); 317 | GST_DEBUG ("strides %d %d %d", stride, stride2, stride2); 318 | return size + 2 * size2; 319 | case AV_PIX_FMT_YUVA420P: 320 | stride = ROUND_UP_4 (width); 321 | h2 = ROUND_UP_X (height, pinfo->y_chroma_shift); 322 | size = stride * h2; 323 | w2 = DIV_ROUND_UP_X (width, pinfo->x_chroma_shift); 324 | stride2 = ROUND_UP_4 (w2); 325 | h2 = DIV_ROUND_UP_X (height, pinfo->y_chroma_shift); 326 | size2 = stride2 * h2; 327 | picture->data[0] = ptr; 328 | picture->data[1] = picture->data[0] + size; 329 | picture->data[2] = picture->data[1] + size2; 330 | picture->data[3] = picture->data[2] + size2; 331 | picture->linesize[0] = stride; 332 | picture->linesize[1] = stride2; 333 | picture->linesize[2] = stride2; 334 | picture->linesize[3] = stride; 335 | GST_DEBUG ("planes %d %d %d %d", 0, size, size + size2, size + 2 * size2); 336 | GST_DEBUG ("strides %d %d %d %d", stride, stride2, stride2, stride); 337 | return 2 * size + 2 * size2; 338 | case AV_PIX_FMT_RGB24: 339 | case AV_PIX_FMT_BGR24: 340 | stride = ROUND_UP_4 (width * 3); 341 | size = stride * height; 342 | picture->data[0] = ptr; 343 | picture->data[1] = NULL; 344 | picture->data[2] = NULL; 345 | picture->data[3] = NULL; 346 | picture->linesize[0] = stride; 347 | picture->linesize[1] = 0; 348 | picture->linesize[2] = 0; 349 | picture->linesize[3] = 0; 350 | return size; 351 | /*case AV_PIX_FMT_AYUV4444: 352 | case AV_PIX_FMT_BGR32: 353 | case AV_PIX_FMT_BGRA32: 354 | case AV_PIX_FMT_RGB32: */ 355 | case AV_PIX_FMT_RGB32: 356 | stride = width * 4; 357 | size = stride * height; 358 | picture->data[0] = ptr; 359 | picture->data[1] = NULL; 360 | picture->data[2] = NULL; 361 | picture->data[3] = NULL; 362 | picture->linesize[0] = stride; 363 | picture->linesize[1] = 0; 364 | picture->linesize[2] = 0; 365 | picture->linesize[3] = 0; 366 | return size; 367 | case AV_PIX_FMT_RGB555: 368 | case AV_PIX_FMT_RGB565: 369 | case AV_PIX_FMT_YUYV422: 370 | case AV_PIX_FMT_UYVY422: 371 | stride = ROUND_UP_4 (width * 2); 372 | size = stride * height; 373 | picture->data[0] = ptr; 374 | picture->data[1] = NULL; 375 | picture->data[2] = NULL; 376 | picture->data[3] = NULL; 377 | picture->linesize[0] = stride; 378 | picture->linesize[1] = 0; 379 | picture->linesize[2] = 0; 380 | picture->linesize[3] = 0; 381 | return size; 382 | case AV_PIX_FMT_UYYVYY411: 383 | /* FIXME, probably not the right stride */ 384 | stride = ROUND_UP_4 (width); 385 | size = stride * height; 386 | picture->data[0] = ptr; 387 | picture->data[1] = NULL; 388 | picture->data[2] = NULL; 389 | picture->data[3] = NULL; 390 | picture->linesize[0] = width + width / 2; 391 | picture->linesize[1] = 0; 392 | picture->linesize[2] = 0; 393 | picture->linesize[3] = 0; 394 | return size + size / 2; 395 | case AV_PIX_FMT_GRAY8: 396 | stride = ROUND_UP_4 (width); 397 | size = stride * height; 398 | picture->data[0] = ptr; 399 | picture->data[1] = NULL; 400 | picture->data[2] = NULL; 401 | picture->data[3] = NULL; 402 | picture->linesize[0] = stride; 403 | picture->linesize[1] = 0; 404 | picture->linesize[2] = 0; 405 | picture->linesize[3] = 0; 406 | return size; 407 | case AV_PIX_FMT_MONOWHITE: 408 | case AV_PIX_FMT_MONOBLACK: 409 | stride = ROUND_UP_4 ((width + 7) >> 3); 410 | size = stride * height; 411 | picture->data[0] = ptr; 412 | picture->data[1] = NULL; 413 | picture->data[2] = NULL; 414 | picture->data[3] = NULL; 415 | picture->linesize[0] = stride; 416 | picture->linesize[1] = 0; 417 | picture->linesize[2] = 0; 418 | picture->linesize[3] = 0; 419 | return size; 420 | case AV_PIX_FMT_PAL8: 421 | /* already forced to be with stride, so same result as other function */ 422 | stride = ROUND_UP_4 (width); 423 | size = stride * height; 424 | picture->data[0] = ptr; 425 | picture->data[1] = ptr + size; /* palette is stored here as 256 32 bit words */ 426 | picture->data[2] = NULL; 427 | picture->data[3] = NULL; 428 | picture->linesize[0] = stride; 429 | picture->linesize[1] = 4; 430 | picture->linesize[2] = 0; 431 | picture->linesize[3] = 0; 432 | return size + 256 * 4; 433 | default: 434 | picture->data[0] = NULL; 435 | picture->data[1] = NULL; 436 | picture->data[2] = NULL; 437 | picture->data[3] = NULL; 438 | return -1; 439 | } 440 | 441 | return 0; 442 | } 443 | 444 | /* Create a GstBuffer of the requested size and caps. 445 | * The memory will be allocated by ffmpeg, making sure it's properly aligned 446 | * for any processing. */ 447 | 448 | GstBuffer * 449 | new_aligned_buffer (gint size) 450 | { 451 | GstBuffer *buf; 452 | guint8 *data; 453 | 454 | data = av_malloc (size); 455 | 456 | buf = gst_buffer_new (); 457 | gst_buffer_append_memory (buf, 458 | gst_memory_new_wrapped (0, data, size, 0, size, data, av_free)); 459 | 460 | return buf; 461 | } 462 | 463 | int 464 | gst_ffmpeg_auto_max_threads (void) 465 | { 466 | static gsize n_threads = 0; 467 | if (g_once_init_enter (&n_threads)) { 468 | int n = 1; 469 | #if defined(_WIN32) 470 | { 471 | const char *s = getenv ("NUMBER_OF_PROCESSORS"); 472 | if (s) { 473 | n = atoi (s); 474 | } 475 | } 476 | #elif defined(__APPLE__) 477 | { 478 | int mib[] = { CTL_HW, HW_NCPU }; 479 | size_t dataSize = sizeof (int); 480 | 481 | if (sysctl (mib, 2, &n, &dataSize, NULL, 0)) { 482 | n = 1; 483 | } 484 | } 485 | #else 486 | n = sysconf (_SC_NPROCESSORS_CONF); 487 | #endif 488 | if (n < 1) 489 | n = 1; 490 | 491 | g_once_init_leave (&n_threads, n); 492 | } 493 | 494 | return (int) (n_threads); 495 | } 496 | -------------------------------------------------------------------------------- /ext/libav/gstavutils.h: -------------------------------------------------------------------------------- 1 | /* GStreamer 2 | * Copyright (C) <2009> Edward Hervey 3 | * 4 | * This library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Library General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2 of the License, or (at your option) any later version. 8 | * 9 | * This library is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Library General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Library General Public 15 | * License along with this library; if not, write to the 16 | * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, 17 | * Boston, MA 02110-1301, USA. 18 | */ 19 | 20 | #ifndef __GST_FFMPEG_UTILS_H__ 21 | #define __GST_FFMPEG_UTILS_H__ 22 | 23 | #ifdef HAVE_CONFIG_H 24 | #include "config.h" 25 | #endif 26 | 27 | #include 28 | #include 29 | 30 | #include 31 | 32 | /* Introduced since ffmpeg version 4.3 33 | * 34 | * Note: Not all ffmpeg encoders seem to be reusable after flushing/draining. 35 | * So if ffmpeg encoder doesn't support it, we should reopen encoding session. 36 | * 37 | * Before ffmpeg 4.3, avcodec_flush_buffers() was implemented in 38 | * libavcodec/decodec.c but it was moved to libavcodec/utils.c and it would be 39 | * accepted if encoder supports AV_CODEC_CAP_ENCODER_FLUSH flag. 40 | * That implies that avcodec_flush_buffers() wasn't intended to be working 41 | * properly for encoders. 42 | */ 43 | #ifndef AV_CODEC_CAP_ENCODER_FLUSH 44 | /* 45 | * This encoder can be flushed using avcodec_flush_buffers(). If this flag is 46 | * not set, the encoder must be closed and reopened to ensure that no frames 47 | * remain pending. 48 | */ 49 | #define AV_CODEC_CAP_ENCODER_FLUSH (1 << 21) 50 | #endif 51 | 52 | /* 53 | *Get the size of an picture 54 | */ 55 | int 56 | gst_ffmpeg_avpicture_get_size (int pix_fmt, int width, int height); 57 | 58 | /* 59 | * Fill in pointers in an AVFrame, aligned by 4 (required by X). 60 | */ 61 | 62 | int 63 | gst_ffmpeg_avpicture_fill (AVFrame * picture, 64 | uint8_t * ptr, 65 | enum AVPixelFormat pix_fmt, 66 | int width, 67 | int height); 68 | 69 | /* 70 | * Convert from/to a GStreamer <-> FFMpeg timestamp. 71 | */ 72 | static inline guint64 73 | gst_ffmpeg_time_ff_to_gst (gint64 pts, AVRational base) 74 | { 75 | guint64 out; 76 | 77 | if (pts == AV_NOPTS_VALUE){ 78 | out = GST_CLOCK_TIME_NONE; 79 | } else { 80 | AVRational bq = { 1, GST_SECOND }; 81 | out = av_rescale_q (pts, base, bq); 82 | } 83 | 84 | return out; 85 | } 86 | 87 | static inline gint64 88 | gst_ffmpeg_time_gst_to_ff (guint64 time, AVRational base) 89 | { 90 | gint64 out; 91 | 92 | if (!GST_CLOCK_TIME_IS_VALID (time) || base.num == 0) { 93 | out = AV_NOPTS_VALUE; 94 | } else { 95 | AVRational bq = { 1, GST_SECOND }; 96 | out = av_rescale_q (time, bq, base); 97 | } 98 | 99 | return out; 100 | } 101 | 102 | void 103 | gst_ffmpeg_init_pix_fmt_info(void); 104 | 105 | int 106 | gst_ffmpeg_auto_max_threads(void); 107 | 108 | const gchar * 109 | gst_ffmpeg_get_codecid_longname (enum AVCodecID codec_id); 110 | 111 | gint 112 | av_smp_format_depth(enum AVSampleFormat smp_fmt); 113 | 114 | GstBuffer * 115 | new_aligned_buffer (gint size); 116 | 117 | #endif /* __GST_FFMPEG_UTILS_H__ */ 118 | -------------------------------------------------------------------------------- /ext/libav/gstavviddec.h: -------------------------------------------------------------------------------- 1 | /* GStreamer 2 | * Copyright (C) <1999> Erik Walthinsen 3 | * 4 | * This library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Library General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2 of the License, or (at your option) any later version. 8 | * 9 | * This library is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Library General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Library General Public 15 | * License along with this library; if not, write to the 16 | * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, 17 | * Boston, MA 02110-1301, USA. 18 | */ 19 | #ifndef __GST_FFMPEGVIDDEC_H__ 20 | #define __GST_FFMPEGVIDDEC_H__ 21 | 22 | #include 23 | #include 24 | #include 25 | 26 | G_BEGIN_DECLS 27 | 28 | typedef struct _GstFFMpegVidDec GstFFMpegVidDec; 29 | struct _GstFFMpegVidDec 30 | { 31 | GstVideoDecoder parent; 32 | 33 | GstVideoCodecState *input_state; 34 | GstVideoCodecState *output_state; 35 | 36 | /* decoding */ 37 | AVCodecContext *context; 38 | AVFrame *picture; 39 | GstVideoMultiviewMode picture_multiview_mode; 40 | GstVideoMultiviewFlags picture_multiview_flags; 41 | gint stride[AV_NUM_DATA_POINTERS]; 42 | gboolean opened; 43 | 44 | /* current output pictures */ 45 | enum AVPixelFormat pic_pix_fmt; 46 | gint pic_width; 47 | gint pic_height; 48 | gint pic_par_n; 49 | gint pic_par_d; 50 | gint pic_interlaced; 51 | /* GST_VIDEO_BUFFER_FLAG_RFF | GST_VIDEO_BUFFER_FLAG_TFF */ 52 | gint pic_field_order; 53 | gboolean pic_field_order_changed; 54 | GstVideoMultiviewMode cur_multiview_mode; 55 | GstVideoMultiviewFlags cur_multiview_flags; 56 | /* current context */ 57 | gint ctx_ticks; 58 | gint ctx_time_d; 59 | gint ctx_time_n; 60 | GstBuffer *palette; 61 | 62 | guint8 *padded; 63 | gint padded_size; 64 | 65 | /* some properties */ 66 | enum AVDiscard skip_frame; 67 | gint lowres; 68 | gboolean direct_rendering; 69 | int max_threads; 70 | gboolean output_corrupt; 71 | guint thread_type; 72 | 73 | GstCaps *last_caps; 74 | 75 | /* Internally used for direct rendering */ 76 | GstBufferPool *internal_pool; 77 | gint pool_width; 78 | gint pool_height; 79 | enum AVPixelFormat pool_format; 80 | GstVideoInfo pool_info; 81 | }; 82 | 83 | typedef struct _GstFFMpegVidDecClass GstFFMpegVidDecClass; 84 | 85 | struct _GstFFMpegVidDecClass 86 | { 87 | GstVideoDecoderClass parent_class; 88 | 89 | AVCodec *in_plugin; 90 | }; 91 | 92 | G_END_DECLS 93 | 94 | #endif 95 | -------------------------------------------------------------------------------- /ext/libav/gstavvidenc.h: -------------------------------------------------------------------------------- 1 | /* GStreamer 2 | * Copyright (C) <1999> Erik Walthinsen 3 | * 4 | * This library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Library General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2 of the License, or (at your option) any later version. 8 | * 9 | * This library is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Library General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Library General Public 15 | * License along with this library; if not, write to the 16 | * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, 17 | * Boston, MA 02110-1301, USA. 18 | */ 19 | 20 | /* First, include the header file for the plugin, to bring in the 21 | * object definition and other useful things. 22 | */ 23 | 24 | #ifndef __GST_FFMPEGVIDENC_H__ 25 | #define __GST_FFMPEGVIDENC_H__ 26 | 27 | #include 28 | #include 29 | #include 30 | 31 | G_BEGIN_DECLS 32 | 33 | typedef struct _GstFFMpegVidEnc GstFFMpegVidEnc; 34 | 35 | struct _GstFFMpegVidEnc 36 | { 37 | GstVideoEncoder parent; 38 | 39 | GstVideoCodecState *input_state; 40 | 41 | AVCodecContext *context; 42 | AVFrame *picture; 43 | gboolean opened; 44 | gboolean need_reopen; 45 | gboolean discont; 46 | guint pass; 47 | gfloat quantizer; 48 | 49 | /* statistics file */ 50 | gchar *filename; 51 | FILE *file; 52 | 53 | /* cache */ 54 | guint8 *working_buf; 55 | gsize working_buf_size; 56 | 57 | AVCodecContext *refcontext; 58 | }; 59 | 60 | typedef struct _GstFFMpegVidEncClass GstFFMpegVidEncClass; 61 | 62 | struct _GstFFMpegVidEncClass 63 | { 64 | GstVideoEncoderClass parent_class; 65 | 66 | AVCodec *in_plugin; 67 | GstPadTemplate *srctempl, *sinktempl; 68 | }; 69 | 70 | G_END_DECLS 71 | 72 | #endif /* __GST_FFMPEGVIDENC_H__ */ 73 | -------------------------------------------------------------------------------- /ext/libav/meson.build: -------------------------------------------------------------------------------- 1 | sources = [ 2 | 'gstav.c', 3 | 'gstavprotocol.c', 4 | 'gstavcodecmap.c', 5 | 'gstavutils.c', 6 | 'gstavaudenc.c', 7 | 'gstavvidenc.c', 8 | 'gstavauddec.c', 9 | 'gstavviddec.c', 10 | 'gstavcfg.c', 11 | 'gstavdemux.c', 12 | 'gstavmux.c', 13 | 'gstavdeinterlace.c', 14 | ] 15 | 16 | gstlibav_plugin = library('gstlibav', 17 | sources, 18 | c_args : gst_libav_args, 19 | include_directories : [configinc], 20 | dependencies : libav_deps + [gst_dep, gstbase_dep, gstvideo_dep, 21 | gstaudio_dep, gstpbutils_dep], 22 | install : true, 23 | install_dir : plugins_install_dir, 24 | ) 25 | pkgconfig.generate(gstlibav_plugin, install_dir : plugins_pkgconfig_install_dir) 26 | plugins += [gstlibav_plugin] 27 | -------------------------------------------------------------------------------- /hooks/pre-commit.hook: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # Check that the code follows a consistant code style 4 | # 5 | 6 | # Check for existence of indent, and error out if not present. 7 | # On some *bsd systems the binary seems to be called gnunindent, 8 | # so check for that first. 9 | 10 | version=`gnuindent --version 2>/dev/null` 11 | if test "x$version" = "x"; then 12 | version=`gindent --version 2>/dev/null` 13 | if test "x$version" = "x"; then 14 | version=`indent --version 2>/dev/null` 15 | if test "x$version" = "x"; then 16 | echo "GStreamer git pre-commit hook:" 17 | echo "Did not find GNU indent, please install it before continuing." 18 | exit 1 19 | else 20 | INDENT=indent 21 | fi 22 | else 23 | INDENT=gindent 24 | fi 25 | else 26 | INDENT=gnuindent 27 | fi 28 | 29 | case `$INDENT --version` in 30 | GNU*) 31 | ;; 32 | default) 33 | echo "GStreamer git pre-commit hook:" 34 | echo "Did not find GNU indent, please install it before continuing." 35 | echo "(Found $INDENT, but it doesn't seem to be GNU indent)" 36 | exit 1 37 | ;; 38 | esac 39 | 40 | INDENT_PARAMETERS="--braces-on-if-line \ 41 | --case-brace-indentation0 \ 42 | --case-indentation2 \ 43 | --braces-after-struct-decl-line \ 44 | --line-length80 \ 45 | --no-tabs \ 46 | --cuddle-else \ 47 | --dont-line-up-parentheses \ 48 | --continuation-indentation4 \ 49 | --honour-newlines \ 50 | --tab-size8 \ 51 | --indent-level2 \ 52 | --leave-preprocessor-space" 53 | 54 | echo "--Checking style--" 55 | for file in `git diff-index --cached --name-only HEAD --diff-filter=ACMR| grep "\.c$"` ; do 56 | # nf is the temporary checkout. This makes sure we check against the 57 | # revision in the index (and not the checked out version). 58 | nf=`git checkout-index --temp ${file} | cut -f 1` 59 | newfile=`mktemp /tmp/${nf}.XXXXXX` || exit 1 60 | $INDENT ${INDENT_PARAMETERS} \ 61 | $nf -o $newfile 2>> /dev/null 62 | # FIXME: Call indent twice as it tends to do line-breaks 63 | # different for every second call. 64 | $INDENT ${INDENT_PARAMETERS} \ 65 | $newfile 2>> /dev/null 66 | diff -u -p "${nf}" "${newfile}" 67 | r=$? 68 | rm "${newfile}" 69 | rm "${nf}" 70 | if [ $r != 0 ] ; then 71 | echo "=================================================================================================" 72 | echo " Code style error in: $file " 73 | echo " " 74 | echo " Please fix before committing. Don't forget to run git add before trying to commit again. " 75 | echo " If the whole file is to be committed, this should work (run from the top-level directory): " 76 | echo " " 77 | echo " gst-indent $file; git add $file; git commit" 78 | echo " " 79 | echo "=================================================================================================" 80 | exit 1 81 | fi 82 | done 83 | echo "--Checking style pass--" 84 | -------------------------------------------------------------------------------- /meson.build: -------------------------------------------------------------------------------- 1 | project('gst-libav', 'c', 'cpp', 2 | version : '1.19.2', 3 | meson_version : '>= 0.54', 4 | default_options : [ 'warning_level=1', 5 | 'buildtype=debugoptimized' ]) 6 | 7 | gst_version = meson.project_version() 8 | version_arr = gst_version.split('.') 9 | gst_version_major = version_arr[0].to_int() 10 | gst_version_minor = version_arr[1].to_int() 11 | gst_version_micro = version_arr[2].to_int() 12 | if version_arr.length() == 4 13 | gst_version_nano = version_arr[3].to_int() 14 | else 15 | gst_version_nano = 0 16 | endif 17 | 18 | api_version = '1.0' 19 | libavfilter_dep = dependency('libavfilter', version: '>= 7.16.100', 20 | fallback: ['FFmpeg', 'libavfilter_dep']) 21 | libavformat_dep = dependency('libavformat', version: '>= 58.12.100', 22 | fallback: ['FFmpeg', 'libavformat_dep']) 23 | libavcodec_dep = dependency('libavcodec', version: '>= 58.18.100', 24 | fallback: ['FFmpeg', 'libavcodec_dep']) 25 | libavutil_dep = dependency('libavutil', version: '>= 56.14.100', 26 | fallback: ['FFmpeg', 'libavutil_dep']) 27 | 28 | libav_deps = [libavfilter_dep, libavformat_dep, libavcodec_dep, libavutil_dep] 29 | 30 | cc = meson.get_compiler('c') 31 | 32 | check_ffmpeg_src = '''#include 33 | #if LIBAVCODEC_VERSION_MICRO >= 100 34 | /* FFmpeg uses 100+ as its micro version */ 35 | #else 36 | #error libav provider should be FFmpeg 37 | #endif''' 38 | 39 | libav_deps_type_name = '' 40 | 41 | foreach dep: libav_deps 42 | if libav_deps_type_name != '' and dep.type_name() != libav_deps_type_name 43 | error('Libav deps must be either all internal or all external') 44 | endif 45 | libav_deps_type_name = dep.type_name() 46 | endforeach 47 | 48 | if dep.type_name() != 'internal' 49 | if not cc.compiles(check_ffmpeg_src, dependencies : libav_deps, name : 'libav is provided by FFmpeg') 50 | error('Uncompatible libavcodec found') 51 | endif 52 | endif 53 | 54 | cdata = configuration_data() 55 | cdata.set('LIBAV_SOURCE', '"system install"') 56 | cdata.set('PACKAGE_VERSION', '"@0@"'.format(gst_version)) 57 | cdata.set('PACKAGE', '"gst-libav"') 58 | 59 | # GStreamer package name and origin url 60 | gst_package_name = get_option('package-name') 61 | if gst_package_name == '' 62 | if gst_version_nano == 0 63 | gst_package_name = 'GStreamer FFMPEG Plug-ins source release' 64 | elif gst_version_nano == 1 65 | gst_package_name = 'GStreamer FFMPEG Plug-ins git' 66 | else 67 | gst_package_name = 'GStreamer FFMPEG Plug-ins prerelease' 68 | endif 69 | endif 70 | cdata.set_quoted('GST_PACKAGE_NAME', gst_package_name) 71 | cdata.set_quoted('GST_PACKAGE_ORIGIN', get_option('package-origin')) 72 | 73 | 74 | check_headers = [['unistd.h', 'HAVE_UNISTD_H']] 75 | 76 | foreach h : check_headers 77 | if cc.has_header(h.get(0)) 78 | cdata.set(h.get(1), 1) 79 | endif 80 | endforeach 81 | 82 | gst_req = '>= @0@.@1@.0'.format(gst_version_major, gst_version_minor) 83 | gst_dep = dependency('gstreamer-1.0', version : gst_req, 84 | fallback : ['gstreamer', 'gst_dep']) 85 | gstbase_dep = dependency('gstreamer-base-1.0', version : gst_req, 86 | fallback : ['gstreamer', 'gst_base_dep']) 87 | gstcheck_dep = dependency('gstreamer-check-1.0', version : gst_req, 88 | required : get_option('tests'), 89 | fallback : ['gstreamer', 'gst_check_dep']) 90 | 91 | gstvideo_dep = dependency('gstreamer-video-1.0', version : gst_req, 92 | fallback : ['gst-plugins-base', 'video_dep']) 93 | gstaudio_dep = dependency('gstreamer-audio-1.0', version : gst_req, 94 | fallback : ['gst-plugins-base', 'audio_dep']) 95 | gstpbutils_dep = dependency('gstreamer-pbutils-1.0', version : gst_req, 96 | fallback : ['gst-plugins-base', 'pbutils_dep']) 97 | libm = cc.find_library('m', required : false) 98 | 99 | gst_libav_args = ['-DHAVE_CONFIG_H'] 100 | if cc.get_id() == 'msvc' 101 | msvc_args = [ 102 | # Ignore several spurious warnings for things gstreamer does very commonly 103 | # If a warning is completely useless and spammy, use '/wdXXXX' to suppress it 104 | # If a warning is harmless but hard to fix, use '/woXXXX' so it's shown once 105 | # NOTE: Only add warnings here if you are sure they're spurious 106 | '/wd4018', # implicit signed/unsigned conversion 107 | '/wd4146', # unary minus on unsigned (beware INT_MIN) 108 | '/wd4244', # lossy type conversion (e.g. double -> int) 109 | '/wd4305', # truncating type conversion (e.g. double -> float) 110 | cc.get_supported_arguments(['/utf-8']), # set the input encoding to utf-8 111 | 112 | # Enable some warnings on MSVC to match GCC/Clang behaviour 113 | '/w14062', # enumerator 'identifier' in switch of enum 'enumeration' is not handled 114 | '/w14101', # 'identifier' : unreferenced local variable 115 | '/w14189', # 'identifier' : local variable is initialized but not referenced 116 | ] 117 | add_project_arguments(msvc_args, language: ['c', 'cpp']) 118 | endif 119 | 120 | # Symbol visibility 121 | if cc.has_argument('-fvisibility=hidden') 122 | add_project_arguments('-fvisibility=hidden', language: 'c') 123 | endif 124 | 125 | # Don't export any symbols from static ffmpeg libraries 126 | if cc.has_link_argument('-Wl,--exclude-libs=ALL') 127 | add_project_link_arguments('-Wl,--exclude-libs=ALL', language: 'c') 128 | endif 129 | 130 | # Disable strict aliasing 131 | if cc.has_argument('-fno-strict-aliasing') 132 | add_project_arguments('-fno-strict-aliasing', language: 'c') 133 | endif 134 | 135 | if gst_dep.type_name() == 'internal' 136 | gst_proj = subproject('gstreamer') 137 | 138 | if not gst_proj.get_variable('gst_debug') 139 | message('GStreamer debug system is disabled') 140 | add_project_arguments('-Wno-unused', language: 'c') 141 | else 142 | message('GStreamer debug system is enabled') 143 | endif 144 | else 145 | # We can't check that in the case of subprojects as we won't 146 | # be able to build against an internal dependency (which is not built yet) 147 | if not cc.compiles(''' 148 | #include 149 | #ifdef GST_DISABLE_GST_DEBUG 150 | #error "debugging disabled, make compiler fail" 151 | #endif''' , dependencies: gst_dep) 152 | message('GStreamer debug system is disabled') 153 | add_project_arguments('-Wno-unused', language: 'c') 154 | else 155 | message('GStreamer debug system is enabled') 156 | endif 157 | endif 158 | 159 | warning_flags = [ 160 | '-Wmissing-declarations', 161 | '-Wmissing-prototypes', 162 | '-Wold-style-definition', 163 | '-Wredundant-decls', 164 | '-Wundef', 165 | '-Wwrite-strings', 166 | '-Wformat', 167 | '-Wformat-nonliteral', 168 | '-Wformat-security', 169 | '-Winit-self', 170 | '-Wmissing-include-dirs', 171 | '-Waddress', 172 | '-Wno-multichar', 173 | '-Waggregate-return', 174 | '-Wdeclaration-after-statement', 175 | '-Wvla', 176 | '-Wpointer-arith', 177 | ] 178 | 179 | foreach extra_arg : warning_flags 180 | if cc.has_argument (extra_arg) 181 | add_project_arguments([extra_arg], language: 'c') 182 | endif 183 | endforeach 184 | 185 | configinc = include_directories('.') 186 | plugins_install_dir = '@0@/gstreamer-1.0'.format(get_option('libdir')) 187 | 188 | pkgconfig = import('pkgconfig') 189 | plugins_pkgconfig_install_dir = join_paths(plugins_install_dir, 'pkgconfig') 190 | if get_option('default_library') == 'shared' 191 | # If we don't build static plugins there is no need to generate pc files 192 | plugins_pkgconfig_install_dir = disabler() 193 | endif 194 | 195 | plugins = [] 196 | subdir('ext/libav') 197 | subdir('docs') 198 | subdir('tests') 199 | 200 | # Set release date 201 | if gst_version_nano == 0 202 | extract_release_date = find_program('scripts/extract-release-date-from-doap-file.py') 203 | run_result = run_command(extract_release_date, gst_version, files('gst-libav.doap')) 204 | if run_result.returncode() == 0 205 | release_date = run_result.stdout().strip() 206 | cdata.set_quoted('GST_PACKAGE_RELEASE_DATETIME', release_date) 207 | message('Package release date: ' + release_date) 208 | else 209 | # Error out if our release can't be found in the .doap file 210 | error(run_result.stderr()) 211 | endif 212 | endif 213 | 214 | configure_file(output: 'config.h', configuration: cdata) 215 | 216 | python3 = import('python').find_installation() 217 | run_command(python3, '-c', 'import shutil; shutil.copy("hooks/pre-commit.hook", ".git/hooks/pre-commit")') 218 | -------------------------------------------------------------------------------- /meson_options.txt: -------------------------------------------------------------------------------- 1 | option('package-name', type : 'string', yield : true, 2 | description : 'package name to use in plugins') 3 | option('package-origin', type : 'string', 4 | value : 'Unknown package origin', yield : true, 5 | description : 'package origin URL to use in plugins') 6 | option('doc', type : 'feature', value : 'auto', yield: true, 7 | description: 'Enable documentation.') 8 | option('tests', type : 'feature', value : 'auto', yield : true) 9 | -------------------------------------------------------------------------------- /scripts/extract-release-date-from-doap-file.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # 3 | # extract-release-date-from-doap-file.py VERSION DOAP-FILE 4 | # 5 | # Extract release date for the given release version from a DOAP file 6 | # 7 | # Copyright (C) 2020 Tim-Philipp Müller 8 | # 9 | # This library is free software; you can redistribute it and/or 10 | # modify it under the terms of the GNU Library General Public 11 | # License as published by the Free Software Foundation; either 12 | # version 2 of the License, or (at your option) any later version. 13 | # 14 | # This library is distributed in the hope that it will be useful, 15 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | # Library General Public License for more details. 18 | # 19 | # You should have received a copy of the GNU Library General Public 20 | # License along with this library; if not, write to the 21 | # Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, 22 | # Boston, MA 02110-1301, USA. 23 | 24 | import sys 25 | import xml.etree.ElementTree as ET 26 | 27 | if len(sys.argv) != 3: 28 | sys.exit('Usage: {} VERSION DOAP-FILE'.format(sys.argv[0])) 29 | 30 | release_version = sys.argv[1] 31 | doap_fn = sys.argv[2] 32 | 33 | tree = ET.parse(doap_fn) 34 | root = tree.getroot() 35 | 36 | namespaces = {'doap': 'http://usefulinc.com/ns/doap#'} 37 | 38 | for v in root.findall('doap:release/doap:Version', namespaces=namespaces): 39 | if v.findtext('doap:revision', namespaces=namespaces) == release_version: 40 | release_date = v.findtext('doap:created', namespaces=namespaces) 41 | if release_date: 42 | print(release_date) 43 | sys.exit(0) 44 | 45 | sys.exit('Could not find a release with version {} in {}'.format(release_version, doap_fn)) 46 | -------------------------------------------------------------------------------- /tests/check/elements/avaudenc.c: -------------------------------------------------------------------------------- 1 | /* GStreamer 2 | * 3 | * Copyright (C) 2020 Seungha Yang 4 | * 5 | * This library is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Library General Public 7 | * License as published by the Free Software Foundation; either 8 | * version 2 of the License, or (at your option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Library General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Library General Public 16 | * License along with this library; if not, write to the 17 | * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, 18 | * Boston, MA 02110-1301, USA. 19 | */ 20 | 21 | #ifdef HAVE_CONFIG_H 22 | #include "config.h" 23 | #endif 24 | 25 | #include 26 | #include 27 | #include 28 | 29 | GST_START_TEST (test_audioenc_drain) 30 | { 31 | GstHarness *h; 32 | GstAudioInfo info; 33 | GstBuffer *in_buf; 34 | gint i = 0; 35 | gint num_output = 0; 36 | GstFlowReturn ret; 37 | GstSegment segment; 38 | GstCaps *caps; 39 | gint samples_per_buffer = 1024; 40 | gint rate = 44100; 41 | gint size; 42 | GstClockTime duration; 43 | 44 | h = gst_harness_new ("avenc_aac"); 45 | fail_unless (h != NULL); 46 | 47 | gst_audio_info_set_format (&info, GST_AUDIO_FORMAT_F32, rate, 1, NULL); 48 | 49 | caps = gst_audio_info_to_caps (&info); 50 | gst_harness_set_src_caps (h, gst_caps_copy (caps)); 51 | 52 | duration = gst_util_uint64_scale_int (samples_per_buffer, GST_SECOND, rate); 53 | size = samples_per_buffer * GST_AUDIO_INFO_BPF (&info); 54 | 55 | for (i = 0; i < 2; i++) { 56 | in_buf = gst_buffer_new_and_alloc (size); 57 | 58 | gst_buffer_memset (in_buf, 0, 0, size); 59 | 60 | /* small rounding error would be expected, but should be fine */ 61 | GST_BUFFER_PTS (in_buf) = i * duration; 62 | GST_BUFFER_DURATION (in_buf) = duration; 63 | 64 | ret = gst_harness_push (h, in_buf); 65 | 66 | fail_unless (ret == GST_FLOW_OK, "GstFlowReturn was %s", 67 | gst_flow_get_name (ret)); 68 | } 69 | 70 | gst_segment_init (&segment, GST_FORMAT_TIME); 71 | fail_unless (gst_segment_set_running_time (&segment, GST_FORMAT_TIME, 72 | 2 * duration)); 73 | 74 | /* Push new eos event to drain encoder */ 75 | fail_unless (gst_harness_push_event (h, gst_event_new_eos ())); 76 | 77 | /* And start new stream */ 78 | fail_unless (gst_harness_push_event (h, 79 | gst_event_new_stream_start ("new-stream-id"))); 80 | gst_harness_set_src_caps (h, caps); 81 | fail_unless (gst_harness_push_event (h, gst_event_new_segment (&segment))); 82 | 83 | in_buf = gst_buffer_new_and_alloc (size); 84 | 85 | GST_BUFFER_PTS (in_buf) = 2 * duration; 86 | GST_BUFFER_DURATION (in_buf) = duration; 87 | 88 | ret = gst_harness_push (h, in_buf); 89 | fail_unless (ret == GST_FLOW_OK, "GstFlowReturn was %s", 90 | gst_flow_get_name (ret)); 91 | 92 | /* Finish encoding and drain again */ 93 | fail_unless (gst_harness_push_event (h, gst_event_new_eos ())); 94 | do { 95 | GstBuffer *out_buf = NULL; 96 | 97 | out_buf = gst_harness_try_pull (h); 98 | if (out_buf) { 99 | num_output++; 100 | gst_buffer_unref (out_buf); 101 | continue; 102 | } 103 | 104 | break; 105 | } while (1); 106 | 107 | fail_unless (num_output >= 3); 108 | 109 | gst_harness_teardown (h); 110 | } 111 | 112 | GST_END_TEST; 113 | 114 | static Suite * 115 | avaudenc_suite (void) 116 | { 117 | Suite *s = suite_create ("avaudenc"); 118 | TCase *tc_chain = tcase_create ("general"); 119 | 120 | suite_add_tcase (s, tc_chain); 121 | tcase_add_test (tc_chain, test_audioenc_drain); 122 | 123 | return s; 124 | } 125 | 126 | GST_CHECK_MAIN (avaudenc) 127 | -------------------------------------------------------------------------------- /tests/check/elements/avdec_adpcm.c: -------------------------------------------------------------------------------- 1 | /* GStreamer unit tests for avdec_adpcm 2 | * 3 | * Copyright (C) 2009 Tim-Philipp Müller 4 | * 5 | * This library is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Library General Public 7 | * License as published by the Free Software Foundation; either 8 | * version 2 of the License, or (at your option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Library General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Library General Public 16 | * License along with this library; if not, write to the 17 | * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, 18 | * Boston, MA 02110-1301, USA. 19 | */ 20 | 21 | #include 22 | 23 | #include 24 | 25 | static void 26 | pad_added_cb (GstElement * decodebin, GstPad * pad, GstBin * pipeline) 27 | { 28 | GstElement *sink; 29 | 30 | GST_INFO_OBJECT (pad, "got pad"); 31 | 32 | sink = gst_bin_get_by_name (pipeline, "fakesink"); 33 | fail_unless (gst_element_link (decodebin, sink)); 34 | gst_object_unref (sink); 35 | 36 | gst_element_set_state (sink, GST_STATE_PAUSED); 37 | } 38 | 39 | static GstBusSyncReply 40 | error_cb (GstBus * bus, GstMessage * msg, gpointer user_data) 41 | { 42 | if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ERROR) { 43 | const gchar *file = (const gchar *) user_data; 44 | GError *err = NULL; 45 | gchar *dbg = NULL; 46 | 47 | gst_message_parse_error (msg, &err, &dbg); 48 | g_error ("ERROR for %s: %s\n%s\n", file, err->message, dbg); 49 | } 50 | 51 | return GST_BUS_PASS; 52 | } 53 | 54 | static gboolean 55 | decode_file (const gchar * file, gboolean push_mode) 56 | { 57 | GstStateChangeReturn state_ret; 58 | GstElement *sink, *src, *dec, *queue, *pipeline; 59 | GstMessage *msg; 60 | GstBus *bus; 61 | gchar *path; 62 | 63 | pipeline = gst_pipeline_new ("pipeline"); 64 | fail_unless (pipeline != NULL, "Failed to create pipeline!"); 65 | 66 | src = gst_element_factory_make ("filesrc", "filesrc"); 67 | fail_unless (src != NULL, "Failed to create filesrc!"); 68 | 69 | if (push_mode) { 70 | queue = gst_element_factory_make ("queue", "queue"); 71 | } else { 72 | queue = gst_element_factory_make ("identity", "identity"); 73 | } 74 | 75 | dec = gst_element_factory_make ("decodebin", "decodebin"); 76 | fail_unless (dec != NULL, "Failed to create decodebin!"); 77 | 78 | sink = gst_element_factory_make ("fakesink", "fakesink"); 79 | fail_unless (sink != NULL, "Failed to create fakesink!"); 80 | 81 | bus = gst_element_get_bus (pipeline); 82 | 83 | /* kids, don't use a sync handler for this at home, really; we do because 84 | * we just want to abort and nothing else */ 85 | gst_bus_set_sync_handler (bus, error_cb, (gpointer) file, NULL); 86 | 87 | gst_bin_add_many (GST_BIN (pipeline), src, queue, dec, sink, NULL); 88 | gst_element_link_many (src, queue, dec, NULL); 89 | 90 | path = g_build_filename (GST_TEST_FILES_PATH, file, NULL); 91 | GST_LOG ("reading file '%s'", path); 92 | g_object_set (src, "location", path, NULL); 93 | 94 | /* can't link uridecodebin and sink yet, do that later */ 95 | g_signal_connect (dec, "pad-added", G_CALLBACK (pad_added_cb), pipeline); 96 | 97 | state_ret = gst_element_set_state (pipeline, GST_STATE_PAUSED); 98 | fail_unless (state_ret != GST_STATE_CHANGE_FAILURE); 99 | 100 | if (state_ret == GST_STATE_CHANGE_ASYNC) { 101 | GST_LOG ("waiting for pipeline to reach PAUSED state"); 102 | state_ret = gst_element_get_state (pipeline, NULL, NULL, -1); 103 | fail_unless_equals_int (state_ret, GST_STATE_CHANGE_SUCCESS); 104 | } 105 | 106 | state_ret = gst_element_set_state (pipeline, GST_STATE_PLAYING); 107 | fail_unless (state_ret != GST_STATE_CHANGE_FAILURE); 108 | 109 | GST_LOG ("PAUSED, let's decode"); 110 | msg = gst_bus_timed_pop_filtered (bus, 10 * GST_SECOND, GST_MESSAGE_EOS); 111 | GST_LOG ("Done, got EOS message"); 112 | fail_unless (msg != NULL); 113 | gst_message_unref (msg); 114 | gst_object_unref (bus); 115 | 116 | fail_unless_equals_int (gst_element_set_state (pipeline, GST_STATE_NULL), 117 | GST_STATE_CHANGE_SUCCESS); 118 | gst_object_unref (pipeline); 119 | 120 | g_free (path); 121 | 122 | return TRUE; 123 | } 124 | 125 | static void 126 | run_check_for_file (const gchar * filename) 127 | { 128 | gboolean ret; 129 | 130 | /* first, pull-based */ 131 | ret = decode_file (filename, FALSE); 132 | fail_unless (ret == TRUE, "Failed to decode '%s' (pull mode)", filename); 133 | 134 | /* second, push-based */ 135 | ret = decode_file (filename, TRUE); 136 | fail_unless (ret == TRUE, "Failed to decode '%s' (push mode)", filename); 137 | } 138 | 139 | GST_START_TEST (test_low_sample_rate_adpcm) 140 | { 141 | #define MIN_VERSION GST_VERSION_MAJOR, GST_VERSION_MINOR, 0 142 | if (!gst_registry_check_feature_version (gst_registry_get (), "wavparse", 143 | MIN_VERSION) 144 | || !gst_registry_check_feature_version (gst_registry_get (), "decodebin", 145 | MIN_VERSION)) { 146 | g_printerr ("skipping test_low_sample_rate_adpcm: required element " 147 | "wavparse or element decodebin not found\n"); 148 | return; 149 | } 150 | 151 | run_check_for_file ("591809.wav"); 152 | } 153 | 154 | GST_END_TEST; 155 | 156 | static Suite * 157 | avdec_adpcm_suite (void) 158 | { 159 | Suite *s = suite_create ("avdec_adpcm"); 160 | TCase *tc_chain = tcase_create ("general"); 161 | 162 | suite_add_tcase (s, tc_chain); 163 | tcase_skip_broken_test (tc_chain, test_low_sample_rate_adpcm); 164 | 165 | return s; 166 | } 167 | 168 | GST_CHECK_MAIN (avdec_adpcm) 169 | -------------------------------------------------------------------------------- /tests/check/elements/avdemux_ape.c: -------------------------------------------------------------------------------- 1 | /* GStreamer unit tests for avdemux_ape 2 | * 3 | * Copyright (C) 2009 Tim-Philipp Müller 4 | * 5 | * This library is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Library General Public 7 | * License as published by the Free Software Foundation; either 8 | * version 2 of the License, or (at your option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Library General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Library General Public 16 | * License along with this library; if not, write to the 17 | * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, 18 | * Boston, MA 02110-1301, USA. 19 | */ 20 | 21 | #include 22 | 23 | #include 24 | 25 | typedef void (CheckTagsFunc) (const GstTagList * tags, const gchar * file); 26 | 27 | static void 28 | pad_added_cb (GstElement * decodebin, GstPad * pad, GstBin * pipeline) 29 | { 30 | GstElement *sink; 31 | 32 | sink = gst_bin_get_by_name (pipeline, "fakesink"); 33 | fail_unless (gst_element_link (decodebin, sink)); 34 | gst_object_unref (sink); 35 | 36 | gst_element_set_state (sink, GST_STATE_PAUSED); 37 | } 38 | 39 | static GstBusSyncReply 40 | error_cb (GstBus * bus, GstMessage * msg, gpointer user_data) 41 | { 42 | if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ERROR) { 43 | const gchar *file = (const gchar *) user_data; 44 | GError *err = NULL; 45 | gchar *dbg = NULL; 46 | 47 | gst_message_parse_error (msg, &err, &dbg); 48 | g_error ("ERROR for %s: %s\n%s\n", file, err->message, dbg); 49 | } 50 | 51 | return GST_BUS_PASS; 52 | } 53 | 54 | static GstPadProbeReturn 55 | event_probe (GstPad * pad, GstPadProbeInfo * info, gpointer user_data) 56 | { 57 | GstTagList **p_tags = user_data; 58 | GstEvent *event = GST_PAD_PROBE_INFO_EVENT (info); 59 | 60 | if (GST_EVENT_TYPE (event) == GST_EVENT_TAG) { 61 | GST_INFO ("tag event: %" GST_PTR_FORMAT, event); 62 | if (*p_tags == NULL) { 63 | GstTagList *event_tags; 64 | 65 | GST_INFO ("first tag, saving"); 66 | gst_event_parse_tag (event, &event_tags); 67 | *p_tags = gst_tag_list_copy (event_tags); 68 | } 69 | } 70 | return GST_PAD_PROBE_OK; /* keep the data */ 71 | } 72 | 73 | /* FIXME: push_mode not used currently */ 74 | static GstTagList * 75 | read_tags_from_file (const gchar * file, gboolean push_mode) 76 | { 77 | GstStateChangeReturn state_ret; 78 | GstTagList *tags = NULL; 79 | GstElement *sink, *src, *dec, *pipeline; 80 | GstBus *bus; 81 | GstPad *pad; 82 | gchar *path; 83 | 84 | pipeline = gst_pipeline_new ("pipeline"); 85 | fail_unless (pipeline != NULL, "Failed to create pipeline!"); 86 | 87 | src = gst_element_factory_make ("filesrc", "filesrc"); 88 | fail_unless (src != NULL, "Failed to create filesrc!"); 89 | 90 | dec = gst_element_factory_make ("decodebin", "decodebin"); 91 | fail_unless (dec != NULL, "Failed to create decodebin!"); 92 | 93 | sink = gst_element_factory_make ("fakesink", "fakesink"); 94 | fail_unless (sink != NULL, "Failed to create fakesink!"); 95 | 96 | bus = gst_element_get_bus (pipeline); 97 | 98 | /* kids, don't use a sync handler for this at home, really; we do because 99 | * we just want to abort and nothing else */ 100 | gst_bus_set_sync_handler (bus, error_cb, (gpointer) file, NULL); 101 | 102 | gst_bin_add_many (GST_BIN (pipeline), src, dec, sink, NULL); 103 | gst_element_link_many (src, dec, NULL); 104 | 105 | path = g_build_filename (GST_TEST_FILES_PATH, file, NULL); 106 | GST_LOG ("reading file '%s'", path); 107 | g_object_set (src, "location", path, NULL); 108 | 109 | /* can't link uridecodebin and sink yet, do that later */ 110 | g_signal_connect (dec, "pad-added", G_CALLBACK (pad_added_cb), pipeline); 111 | 112 | /* we want to make sure there's a tag event coming out of avdemux_ape 113 | * (ie. the one apedemux generated) */ 114 | pad = gst_element_get_static_pad (sink, "sink"); 115 | gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM, event_probe, 116 | &tags, NULL); 117 | gst_object_unref (pad); 118 | 119 | state_ret = gst_element_set_state (pipeline, GST_STATE_PAUSED); 120 | fail_unless (state_ret != GST_STATE_CHANGE_FAILURE); 121 | 122 | if (state_ret == GST_STATE_CHANGE_ASYNC) { 123 | GST_LOG ("waiting for pipeline to reach PAUSED state"); 124 | state_ret = gst_element_get_state (pipeline, NULL, NULL, -1); 125 | fail_unless_equals_int (state_ret, GST_STATE_CHANGE_SUCCESS); 126 | } 127 | 128 | GST_LOG ("PAUSED, let's retrieve our tags"); 129 | 130 | fail_unless (tags != NULL, "Expected tag event! (%s)", file); 131 | 132 | gst_object_unref (bus); 133 | 134 | fail_unless_equals_int (gst_element_set_state (pipeline, GST_STATE_NULL), 135 | GST_STATE_CHANGE_SUCCESS); 136 | gst_object_unref (pipeline); 137 | 138 | g_free (path); 139 | 140 | GST_INFO ("%s: tags = %" GST_PTR_FORMAT, file, tags); 141 | return tags; 142 | } 143 | 144 | static void 145 | run_check_for_file (const gchar * filename, CheckTagsFunc * check_func) 146 | { 147 | GstTagList *tags; 148 | 149 | /* first, pull-based */ 150 | tags = read_tags_from_file (filename, FALSE); 151 | fail_unless (tags != NULL, "Failed to extract tags from '%s'", filename); 152 | check_func (tags, filename); 153 | gst_tag_list_unref (tags); 154 | } 155 | 156 | #define tag_list_has_tag(taglist,tag) \ 157 | (gst_tag_list_get_value_index((taglist),(tag),0) != NULL) 158 | 159 | /* just make sure avdemux_ape forwarded the tags extracted by apedemux 160 | * (should be the first tag list / tag event too) */ 161 | static void 162 | check_for_apedemux_tags (const GstTagList * tags, const gchar * file) 163 | { 164 | gchar *artist = NULL; 165 | 166 | fail_unless (gst_tag_list_get_string (tags, GST_TAG_ARTIST, &artist)); 167 | fail_unless (artist != NULL); 168 | fail_unless_equals_string (artist, "Marvin Gaye"); 169 | g_free (artist); 170 | 171 | fail_unless (tag_list_has_tag (tags, GST_TAG_CONTAINER_FORMAT)); 172 | 173 | GST_LOG ("all good"); 174 | } 175 | 176 | GST_START_TEST (test_tag_caching) 177 | { 178 | #define MIN_VERSION GST_VERSION_MAJOR, GST_VERSION_MINOR, 0 179 | 180 | if (!gst_registry_check_feature_version (gst_registry_get (), "apedemux", 181 | MIN_VERSION) 182 | || !gst_registry_check_feature_version (gst_registry_get (), "decodebin", 183 | MIN_VERSION)) { 184 | g_printerr ("Skipping test_tag_caching: required element apedemux or " 185 | "decodebin element not found\n"); 186 | return; 187 | } 188 | 189 | run_check_for_file ("586957.ape", check_for_apedemux_tags); 190 | } 191 | 192 | GST_END_TEST; 193 | 194 | static Suite * 195 | avdemux_ape_suite (void) 196 | { 197 | Suite *s = suite_create ("avdemux_ape"); 198 | TCase *tc_chain = tcase_create ("general"); 199 | 200 | suite_add_tcase (s, tc_chain); 201 | tcase_add_test (tc_chain, test_tag_caching); 202 | 203 | return s; 204 | } 205 | 206 | GST_CHECK_MAIN (avdemux_ape) 207 | -------------------------------------------------------------------------------- /tests/check/elements/avvidenc.c: -------------------------------------------------------------------------------- 1 | /* GStreamer 2 | * 3 | * Copyright (C) 2020 Seungha Yang 4 | * 5 | * This library is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Library General Public 7 | * License as published by the Free Software Foundation; either 8 | * version 2 of the License, or (at your option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Library General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Library General Public 16 | * License along with this library; if not, write to the 17 | * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, 18 | * Boston, MA 02110-1301, USA. 19 | */ 20 | 21 | #ifdef HAVE_CONFIG_H 22 | #include "config.h" 23 | #endif 24 | 25 | #include 26 | #include 27 | #include 28 | 29 | GST_START_TEST (test_videoenc_drain) 30 | { 31 | GstHarness *h; 32 | GstVideoInfo info; 33 | GstBuffer *in_buf; 34 | gint i = 0; 35 | gint num_output = 0; 36 | GstFlowReturn ret; 37 | GstSegment segment; 38 | GstCaps *caps; 39 | 40 | h = gst_harness_new ("avenc_mjpeg"); 41 | fail_unless (h != NULL); 42 | 43 | caps = gst_caps_from_string ("video/x-raw,format=I420,width=64,height=64"); 44 | 45 | gst_harness_set_src_caps (h, gst_caps_copy (caps)); 46 | gst_video_info_set_format (&info, GST_VIDEO_FORMAT_I420, 64, 64); 47 | 48 | for (i = 0; i < 2; i++) { 49 | in_buf = gst_buffer_new_and_alloc (GST_VIDEO_INFO_SIZE (&info)); 50 | 51 | GST_BUFFER_PTS (in_buf) = i * GST_SECOND; 52 | GST_BUFFER_DURATION (in_buf) = GST_SECOND; 53 | 54 | ret = gst_harness_push (h, in_buf); 55 | 56 | fail_unless (ret == GST_FLOW_OK, "GstFlowReturn was %s", 57 | gst_flow_get_name (ret)); 58 | } 59 | 60 | gst_segment_init (&segment, GST_FORMAT_TIME); 61 | fail_unless (gst_segment_set_running_time (&segment, GST_FORMAT_TIME, 62 | 2 * GST_SECOND)); 63 | 64 | /* Push new eos event to drain encoder */ 65 | fail_unless (gst_harness_push_event (h, gst_event_new_eos ())); 66 | 67 | /* And start new stream */ 68 | fail_unless (gst_harness_push_event (h, 69 | gst_event_new_stream_start ("new-stream-id"))); 70 | gst_harness_set_src_caps (h, caps); 71 | fail_unless (gst_harness_push_event (h, gst_event_new_segment (&segment))); 72 | 73 | in_buf = gst_buffer_new_and_alloc (GST_VIDEO_INFO_SIZE (&info)); 74 | 75 | GST_BUFFER_PTS (in_buf) = 2 * GST_SECOND; 76 | GST_BUFFER_DURATION (in_buf) = GST_SECOND; 77 | 78 | ret = gst_harness_push (h, in_buf); 79 | fail_unless (ret == GST_FLOW_OK, "GstFlowReturn was %s", 80 | gst_flow_get_name (ret)); 81 | 82 | /* Finish encoding and drain again */ 83 | fail_unless (gst_harness_push_event (h, gst_event_new_eos ())); 84 | do { 85 | GstBuffer *out_buf = NULL; 86 | 87 | out_buf = gst_harness_try_pull (h); 88 | if (out_buf) { 89 | num_output++; 90 | gst_buffer_unref (out_buf); 91 | continue; 92 | } 93 | 94 | break; 95 | } while (1); 96 | 97 | fail_unless_equals_int (num_output, 3); 98 | 99 | gst_harness_teardown (h); 100 | } 101 | 102 | GST_END_TEST; 103 | 104 | static Suite * 105 | avvidenc_suite (void) 106 | { 107 | Suite *s = suite_create ("avvidenc"); 108 | TCase *tc_chain = tcase_create ("general"); 109 | 110 | suite_add_tcase (s, tc_chain); 111 | tcase_add_test (tc_chain, test_videoenc_drain); 112 | 113 | return s; 114 | } 115 | 116 | GST_CHECK_MAIN (avvidenc) 117 | -------------------------------------------------------------------------------- /tests/check/generic/libavcodec-locking.c: -------------------------------------------------------------------------------- 1 | /* GStreamer 2 | * Copyright (C) 2005 Luca Ognibene 3 | * Based (copied) on simple_launch_lines.c 4 | * 5 | * libavcodec-locking.c: Unit test for libavcodec's locks 6 | * 7 | * This library is free software; you can redistribute it and/or 8 | * modify it under the terms of the GNU Library General Public 9 | * License as published by the Free Software Foundation; either 10 | * version 2 of the License, or (at your option) any later version. 11 | * 12 | * This library is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * Library General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU Library General Public 18 | * License along with this library; if not, write to the 19 | * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, 20 | * Boston, MA 02110-1301, USA. 21 | */ 22 | 23 | 24 | #include 25 | #include 26 | 27 | #define NUM_SINKS 10 28 | 29 | static GstElement * 30 | setup_pipeline (const gchar * pipe_descr) 31 | { 32 | GstElement *pipeline; 33 | 34 | pipeline = gst_parse_launch (pipe_descr, NULL); 35 | g_return_val_if_fail (GST_IS_PIPELINE (pipeline), NULL); 36 | return pipeline; 37 | } 38 | 39 | /* 40 | * run_pipeline: 41 | * @pipe: the pipeline to run 42 | * @desc: the description for use in messages 43 | * @events: is a mask of expected events 44 | * @tevent: is the expected terminal event. 45 | * 46 | * the poll call will time out after half a second. 47 | */ 48 | static void 49 | run_pipeline (GstElement * pipe, const gchar * descr, 50 | GstMessageType events, GstMessageType tevent) 51 | { 52 | GstBus *bus; 53 | GstMessage *message; 54 | GstMessageType revent; 55 | GstStateChangeReturn ret; 56 | 57 | g_assert (pipe); 58 | bus = gst_element_get_bus (pipe); 59 | g_assert (bus); 60 | 61 | ret = gst_element_set_state (pipe, GST_STATE_PLAYING); 62 | ret = gst_element_get_state (pipe, NULL, NULL, GST_CLOCK_TIME_NONE); 63 | if (ret != GST_STATE_CHANGE_SUCCESS) { 64 | g_critical ("Couldn't set pipeline to PLAYING"); 65 | goto done; 66 | } 67 | 68 | while (1) { 69 | message = gst_bus_poll (bus, GST_MESSAGE_ANY, GST_SECOND / 2); 70 | 71 | /* always have to pop the message before getting back into poll */ 72 | if (message) { 73 | revent = GST_MESSAGE_TYPE (message); 74 | gst_message_unref (message); 75 | } else { 76 | revent = GST_MESSAGE_UNKNOWN; 77 | } 78 | 79 | if (revent == tevent) { 80 | break; 81 | } else if (revent == GST_MESSAGE_UNKNOWN) { 82 | g_critical ("Unexpected timeout in gst_bus_poll, looking for %d: %s", 83 | tevent, descr); 84 | break; 85 | } else if (revent & events) { 86 | continue; 87 | } 88 | g_critical 89 | ("Unexpected message received of type %d, '%s', looking for %d: %s", 90 | revent, gst_message_type_get_name (revent), tevent, descr); 91 | } 92 | 93 | done: 94 | gst_element_set_state (pipe, GST_STATE_NULL); 95 | gst_object_unref (pipe); 96 | } 97 | 98 | GST_START_TEST (test_libavcodec_locks) 99 | { 100 | gchar *sink[NUM_SINKS + 1], *s, *sinks; 101 | gint i; 102 | 103 | for (i = 0; i < NUM_SINKS; i++) 104 | sink[i] = 105 | g_strdup_printf 106 | (" t.src_%u ! queue ! avenc_mpeg4 ! avdec_mpeg4 ! fakesink sync=true", 107 | i); 108 | 109 | sink[NUM_SINKS] = NULL; 110 | 111 | sinks = g_strjoinv (" ", sink); 112 | 113 | s = g_strdup_printf 114 | ("videotestsrc ! video/x-raw,format=(string)I420,width=320,height=240,framerate=(fraction)10/1 ! tee name=t %s", 115 | sinks); 116 | 117 | run_pipeline (setup_pipeline (s), s, 118 | GST_MESSAGE_ANY & ~(GST_MESSAGE_ERROR | GST_MESSAGE_WARNING), 119 | GST_MESSAGE_UNKNOWN); 120 | g_free (s); 121 | 122 | for (i = 0; i < NUM_SINKS; i++) 123 | g_free (sink[i]); 124 | g_free (sinks); 125 | } 126 | 127 | GST_END_TEST; 128 | 129 | static Suite * 130 | simple_launch_lines_suite (void) 131 | { 132 | gint timeout = 0; 133 | 134 | Suite *s = suite_create ("Pipelines"); 135 | TCase *tc_chain = tcase_create ("linear"); 136 | 137 | if (g_getenv ("CK_DEFAULT_TIMEOUT")) 138 | timeout = atoi (g_getenv ("CK_DEFAULT_TIMEOUT")); 139 | 140 | if (timeout == 0) 141 | timeout = 3; 142 | 143 | /* set multiple of default timeout (random magic value) */ 144 | tcase_set_timeout (tc_chain, timeout * 12); 145 | 146 | suite_add_tcase (s, tc_chain); 147 | 148 | #ifndef GST_DISABLE_PARSE 149 | /* only run this if we haven't been configured with --disable-encoders */ 150 | if (gst_registry_check_feature_version (gst_registry_get (), "avenc_mpeg4", 151 | GST_VERSION_MAJOR, GST_VERSION_MINOR, 0)) { 152 | tcase_add_test (tc_chain, test_libavcodec_locks); 153 | } else { 154 | g_print ("******* Skipping libavcodec_locks test, no encoder available\n"); 155 | } 156 | #endif 157 | 158 | return s; 159 | } 160 | 161 | GST_CHECK_MAIN (simple_launch_lines); 162 | -------------------------------------------------------------------------------- /tests/check/generic/plugin-test.c: -------------------------------------------------------------------------------- 1 | /* GStreamer 2 | * Copyright (C) 2009 Jan Schmidt 3 | * 4 | * Test that the FFmpeg plugin is loadable, and not broken in some stupid 5 | * way. 6 | * 7 | * This library is free software; you can redistribute it and/or 8 | * modify it under the terms of the GNU Library General Public 9 | * License as published by the Free Software Foundation; either 10 | * version 2 of the License, or (at your option) any later version. 11 | * 12 | * This library is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * Library General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU Library General Public 18 | * License along with this library; if not, write to the 19 | * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, 20 | * Boston, MA 02110-1301, USA. 21 | */ 22 | 23 | 24 | #include 25 | #include 26 | 27 | GST_START_TEST (test_libav_plugin) 28 | { 29 | GstPlugin *plugin = gst_plugin_load_by_name ("libav"); 30 | 31 | fail_if (plugin == NULL, "Could not load FFmpeg plugin"); 32 | 33 | gst_object_unref (plugin); 34 | 35 | } 36 | 37 | GST_END_TEST; 38 | 39 | GST_START_TEST (test_libav_update_reg) 40 | { 41 | GstElement *encoder, *muxer, *decoder; 42 | 43 | /* Ask for elements the first time */ 44 | encoder = gst_element_factory_make ("avenc_mpeg2video", "sink"); 45 | GST_DEBUG ("Creating element avenc_mpeg2video %p", encoder); 46 | fail_unless (encoder != NULL); 47 | 48 | decoder = gst_element_factory_make ("avdec_mpeg2video", "sink"); 49 | GST_DEBUG ("Creating element avdec_mpeg2video %p", decoder); 50 | fail_unless (decoder != NULL); 51 | 52 | muxer = gst_element_factory_make ("avmux_dvd", "sink"); 53 | GST_DEBUG ("Creating element avmux_dvd %p", muxer); 54 | fail_unless (muxer != NULL); 55 | 56 | gst_object_unref (encoder); 57 | gst_object_unref (decoder); 58 | gst_object_unref (muxer); 59 | 60 | GST_DEBUG ("calls gst_update_registry"); 61 | gst_update_registry (); 62 | 63 | /* Ask for elements the second time */ 64 | 65 | encoder = gst_element_factory_make ("avenc_mpeg2video", "sink"); 66 | GST_DEBUG ("Creating element avenc_mpeg2video %p", encoder); 67 | fail_unless (encoder != NULL); 68 | 69 | decoder = gst_element_factory_make ("avdec_mpeg2video", "sink"); 70 | GST_DEBUG ("Creating element avdec_mpeg2video %p", decoder); 71 | fail_unless (decoder != NULL); 72 | 73 | muxer = gst_element_factory_make ("avmux_dvd", "sink"); 74 | GST_DEBUG ("Creating element avmux_dvd %p", muxer); 75 | fail_unless (muxer != NULL); 76 | 77 | gst_object_unref (encoder); 78 | gst_object_unref (decoder); 79 | gst_object_unref (muxer); 80 | } 81 | 82 | GST_END_TEST; 83 | 84 | static Suite * 85 | plugin_test_suite (void) 86 | { 87 | Suite *s = suite_create ("Plugin"); 88 | TCase *tc_chain = tcase_create ("existence"); 89 | 90 | suite_add_tcase (s, tc_chain); 91 | 92 | tcase_add_test (tc_chain, test_libav_plugin); 93 | tcase_add_test (tc_chain, test_libav_update_reg); 94 | 95 | return s; 96 | } 97 | 98 | GST_CHECK_MAIN (plugin_test); 99 | -------------------------------------------------------------------------------- /tests/check/gst-libav.supp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GStreamer/gst-libav/4f649c9556ce5b4501363885995554598303e01c/tests/check/gst-libav.supp -------------------------------------------------------------------------------- /tests/check/meson.build: -------------------------------------------------------------------------------- 1 | # name, condition when to skip the test and extra dependencies 2 | libav_tests = [ 3 | [ 'elements/avaudenc' ], 4 | [ 'elements/avdec_adpcm' ], 5 | [ 'elements/avdemux_ape' ], 6 | [ 'elements/avvidenc' ], 7 | [ 'generic/libavcodec-locking' ], 8 | [ 'generic/plugin-test' ] 9 | ] 10 | 11 | test_defines = [ 12 | '-UG_DISABLE_ASSERT', 13 | '-UG_DISABLE_CAST_CHECKS', 14 | '-DGST_CHECK_TEST_ENVIRONMENT_BEACON="GST_PLUGIN_LOADING_WHITELIST"', 15 | '-DGST_TEST_FILES_PATH="' + meson.current_source_dir() + '/../files"', 16 | '-DGST_USE_UNSTABLE_API', 17 | ] 18 | 19 | pluginsdirs = [] 20 | if gst_dep.type_name() == 'pkgconfig' 21 | pbase = dependency('gstreamer-plugins-base-' + api_version, required: true) 22 | pluginsdirs = [gst_dep.get_pkgconfig_variable('pluginsdir'), 23 | pbase.get_pkgconfig_variable('pluginsdir')] 24 | gst_plugin_scanner_dir = gst_dep.get_pkgconfig_variable('pluginscannerdir') 25 | else 26 | gst_plugin_scanner_dir = subproject('gstreamer').get_variable('gst_scanner_dir') 27 | endif 28 | gst_plugin_scanner_path = join_paths(gst_plugin_scanner_dir, 'gst-plugin-scanner') 29 | 30 | # FIXME: check, also + PTHREAD_CFLAGS 31 | test_deps = [gst_dep, gstbase_dep, gstcheck_dep, gstaudio_dep, 32 | gstvideo_dep, gstpbutils_dep] 33 | 34 | # FIXME: add valgrind suppression common/gst.supp gst-libav.supp 35 | foreach t : libav_tests 36 | fname = '@0@.c'.format(t.get(0)) 37 | test_name = t.get(0).underscorify() 38 | extra_sources = t.get(3, [ ]) 39 | extra_deps = t.get(2, [ ]) 40 | skip_test = t.get(1, false) 41 | if not skip_test 42 | env = environment() 43 | env.set('GST_PLUGIN_SYSTEM_PATH_1_0', '') 44 | env.set('CK_DEFAULT_TIMEOUT', '20') 45 | env.set('GST_PLUGIN_LOADING_WHITELIST', 'gstreamer', 'gst-plugins-base', 46 | 'gst-libav@' + meson.build_root()) 47 | env.set('GST_PLUGIN_PATH_1_0', [meson.build_root()] + pluginsdirs) 48 | env.set('GSETTINGS_BACKEND', 'memory') 49 | 50 | env.set('GST_REGISTRY', join_paths(meson.current_build_dir(), '@0@.registry'.format(test_name))) 51 | env.set('GST_PLUGIN_SCANNER_1_0', gst_plugin_scanner_path) 52 | exe = executable(test_name, fname, extra_sources, 53 | include_directories : [configinc], 54 | c_args : ['-DHAVE_CONFIG_H=1' ] + test_defines, 55 | dependencies : [libm] + test_deps + extra_deps, 56 | ) 57 | test(test_name, exe, env: env, timeout: 3 * 60) 58 | endif 59 | endforeach 60 | 61 | -------------------------------------------------------------------------------- /tests/files/586957.ape: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GStreamer/gst-libav/4f649c9556ce5b4501363885995554598303e01c/tests/files/586957.ape -------------------------------------------------------------------------------- /tests/files/591809.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GStreamer/gst-libav/4f649c9556ce5b4501363885995554598303e01c/tests/files/591809.wav -------------------------------------------------------------------------------- /tests/meson.build: -------------------------------------------------------------------------------- 1 | if not get_option('tests').disabled() and gstcheck_dep.found() 2 | subdir('check') 3 | endif 4 | --------------------------------------------------------------------------------